home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / comm / mail / YAM23src.lha / Source / YAM_UT.c < prev    next >
C/C++ Source or Header  |  2001-05-11  |  91KB  |  3,027 lines

  1. /***************************************************************************
  2.  
  3.  YAM - Yet Another Mailer
  4.  Copyright (C) 1995-2000 by Marcel Beck <mbeck@yam.ch>
  5.  Copyright (C) 2000-2001 by YAM Open Source Team
  6.  
  7.  This program is free software; you can redistribute it and/or modify
  8.  it under the terms of the GNU General Public License as published by
  9.  the Free Software Foundation; either version 2 of the License, or
  10.  (at your option) any later version.
  11.  
  12.  This program is distributed in the hope that it will be useful,
  13.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  GNU General Public License for more details.
  16.  
  17.  You should have received a copy of the GNU General Public License
  18.  along with this program; if not, write to the Free Software
  19.  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20.  
  21.  YAM Official Support Site :  http://www.yam.ch
  22.  YAM OpenSource project    :  http://sourceforge.net/projects/yamos/
  23.  
  24.  $Id: YAM_UT.c,v 1.28 2001/05/11 09:00:00 damato Exp $
  25.  
  26. ***************************************************************************/
  27.  
  28. #include "YAM.h"
  29.  
  30. /***************************************************************************
  31.  Utilities
  32. ***************************************************************************/
  33.  
  34. /* local protos */
  35. LOCAL int GetWord(char **rptr, char *wbuf, int max);
  36. LOCAL char *ReflowParagraph(char *start, char *end, int lmax, char *dest);
  37. LOCAL char *RemoveQuoteString(char *start, char *end, char *quot, char *dest);
  38. LOCAL char *InsertQuoteString(char *start, char *quote, FILE *out);
  39. LOCAL void SaveParagraph(char *start, char *end, char *prefix, FILE *out);
  40. LOCAL char *FileToBuffer(char *file);
  41. LOCAL int TZtoMinutes(char *tzone);
  42. LOCAL BOOL GetPackMethod(int xpktype, char **method, int *eff);
  43. LOCAL BOOL CompressMailFile(char *src, char *dst, char *passwd, char *method, int eff);
  44. LOCAL BOOL UncompressMailFile(char *src, char *dst, char *passwd);
  45. LOCAL void AppendToLogfile(int id, char *text, void *a1, void *a2, void *a3, void *a4);
  46. LOCAL char *IdentifyFileDT(char *fname);
  47. void SAVEDS ASM putChar(REG(a0, struct Hook *hook), REG(a1, char c), REG(a2, struct Locale *locale));
  48.  
  49.  
  50. /*** Requesters ***/
  51. /// StringRequest
  52. //  Puts up a string requester
  53. int StringRequest(char *string, int size, char *title, char *body, char *yestext, char *alttext, char *notext, BOOL secret, APTR parent)
  54. {
  55.    APTR bt_okay, bt_middle, bt_cancel, wi_sr, st_in;
  56.    int ret_code = -1;
  57.  
  58.    wi_sr = WindowObject,
  59.       MUIA_Window_Title, title ? title : "YAM",
  60.       MUIA_Window_RefWindow, parent,
  61.       MUIA_Window_LeftEdge, MUIV_Window_LeftEdge_Centered,
  62.       MUIA_Window_TopEdge, MUIV_Window_TopEdge_Centered,
  63.       MUIA_Window_ID, MAKE_ID('S','R','E','Q'),
  64.       WindowContents, VGroup,
  65.          Child, VGroup,
  66.             GroupFrame,
  67.             MUIA_Background, MUII_GroupBack,
  68.             Child, LLabel(body),
  69.             Child, st_in = secret ? MakePassString("") : MakeString(size, ""),
  70.          End,
  71.          Child, ColGroup(3),
  72.             Child, bt_okay = MakeButton(yestext),
  73.             Child, bt_middle = alttext ? MakeButton(alttext) : HSpace(0),
  74.             Child, bt_cancel = MakeButton(notext),
  75.          End,
  76.       End,
  77.    End;
  78.    setstring(st_in, string);
  79.    set(wi_sr, MUIA_Window_ActiveObject, st_in);
  80.    set(G->App, MUIA_Application_Sleep, TRUE);
  81.    DoMethod(G->App, OM_ADDMEMBER, wi_sr);
  82.    DoMethod(bt_okay  , MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 1);
  83.    DoMethod(bt_middle, MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 2);
  84.    DoMethod(bt_cancel, MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 3);
  85.    DoMethod(st_in, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, G->App, 2, MUIM_Application_ReturnID, 1);
  86.    DoMethod(wi_sr, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, G->App, 2, MUIM_Application_ReturnID, 3);
  87.    if (!SafeOpenWindow(wi_sr)) ret_code = 0;
  88.    else while (ret_code == -1)
  89.    {
  90.       ULONG signals;
  91.       switch (DoMethod(G->App, MUIM_Application_Input, &signals))
  92.       {
  93.          case 1: ret_code = 1; break;
  94.          case 2: ret_code = 2; break;
  95.          case 3: ret_code = 0; break;
  96.       }
  97.       if (ret_code == -1 && signals) Wait(signals);
  98.    }
  99.    if (ret_code > 0) GetMUIString(string, st_in);
  100.    DoMethod(G->App, OM_REMMEMBER, wi_sr);
  101.    set(G->App, MUIA_Application_Sleep, FALSE);
  102.    return ret_code;
  103. }
  104. ///
  105. /// FolderRequest
  106. //  Allows user to choose a folder from a list
  107. struct Folder *FolderRequest(char *title, char *body, char *yestext, char *notext, struct Folder *exclude, APTR parent)
  108. {
  109.    static int lastactive;
  110.    struct Folder **flist, *folder = (struct Folder *)-1;
  111.    int act, i;
  112.    char *fname;
  113.    APTR bt_okay, bt_cancel, wi_fr, lv_folder;
  114.  
  115.    wi_fr = WindowObject,
  116.       MUIA_Window_Title, title ? title : "YAM",
  117.       MUIA_Window_RefWindow, parent,
  118.       MUIA_Window_LeftEdge, MUIV_Window_LeftEdge_Centered,
  119.       MUIA_Window_TopEdge, MUIV_Window_TopEdge_Centered,
  120.       MUIA_Window_ID, MAKE_ID('F','R','E','Q'),
  121.       WindowContents, VGroup,
  122.          Child, LLabel(body),
  123.          Child, lv_folder = ListviewObject,
  124.             MUIA_CycleChain, 1,
  125.             MUIA_Listview_DoubleClick, TRUE,
  126.             MUIA_Listview_List, ListObject,
  127.                InputListFrame,
  128.                MUIA_List_AutoVisible, TRUE,
  129.             End,
  130.          End,
  131.          Child, ColGroup(3),
  132.             Child, bt_okay = MakeButton(yestext),
  133.             Child, HSpace(0),
  134.             Child, bt_cancel = MakeButton(notext),
  135.          End,
  136.       End,
  137.    End;
  138.    if (wi_fr)
  139.    {
  140.       flist = FO_CreateList();
  141.       for (i = 1; i <= (int)*flist; i++) if (flist[i] != exclude) if (flist[i]->Type != FT_SEPARATOR)
  142.          DoMethod(lv_folder, MUIM_List_InsertSingle, flist[i]->Name, MUIV_List_Insert_Bottom);
  143.       free(flist);
  144.       set(lv_folder, MUIA_List_Active, lastactive);
  145.       set(wi_fr, MUIA_Window_ActiveObject, lv_folder);
  146.       set(G->App, MUIA_Application_Sleep, TRUE);
  147.       DoMethod(G->App, OM_ADDMEMBER, wi_fr);
  148.       DoMethod(bt_okay  , MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 1);
  149.       DoMethod(bt_cancel, MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 3);
  150.       DoMethod(lv_folder, MUIM_Notify, MUIA_Listview_DoubleClick, MUIV_EveryTime, G->App, 2, MUIM_Application_ReturnID, 1);
  151.       DoMethod(wi_fr, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, G->App, 2, MUIM_Application_ReturnID, 3);
  152.       if (!SafeOpenWindow(wi_fr)) folder = NULL;
  153.       else while (folder == (struct Folder *)-1)
  154.       {
  155.          ULONG signals, oo = DoMethod(G->App, MUIM_Application_Input, &signals);
  156.          switch (oo)
  157.          {
  158.             case 1:
  159.                get(lv_folder, MUIA_List_Active, &act);
  160.                DoMethod(lv_folder, MUIM_List_GetEntry, act, &fname);
  161.                if ((folder = FO_GetFolderByName(fname, NULL))) lastactive = act;
  162.                break;
  163.             case 3: folder = NULL; break;
  164.          }
  165.          if (folder == (struct Folder *)-1 && signals) Wait(signals);
  166.       }
  167.       DoMethod(G->App, OM_REMMEMBER, wi_fr);
  168.       set(G->App, MUIA_Application_Sleep, FALSE);
  169.    }
  170.    return folder;
  171. }
  172. ///
  173. /// AttachRequest
  174. //  Allows user to select a message part (attachment) from a list
  175. struct Part *AttachRequest(char *title, char *body, char *yestext, char *notext, int winnum, int mode, APTR parent)
  176. {
  177.    struct Part *retpart = (struct Part *)-1, *part, *prevpart;
  178.    APTR bt_okay, bt_cancel, wi_ar, lv_attach;
  179.  
  180.    wi_ar = WindowObject,
  181.       MUIA_Window_Title, title ? title : "YAM",
  182.       MUIA_Window_RefWindow, parent,
  183.       MUIA_Window_LeftEdge, MUIV_Window_LeftEdge_Centered,
  184.       MUIA_Window_TopEdge, MUIV_Window_TopEdge_Centered,
  185.       MUIA_Window_ID, MAKE_ID('A','R','E','Q'),
  186.       WindowContents, VGroup,
  187.          Child, LLabel(body),
  188.          Child, lv_attach = NListviewObject,
  189.             MUIA_CycleChain, 1,
  190.             MUIA_NListview_NList, NListObject,
  191.                InputListFrame,
  192.                MUIA_NList_Title,                  TRUE,
  193.                MUIA_NList_DoubleClick,     TRUE,
  194.                MUIA_NList_MultiSelect,     (mode&ATTREQ_MULTI) ? MUIV_NList_MultiSelect_Default : MUIV_NList_MultiSelect_None,
  195.                MUIA_NList_DisplayHook,     &RE_LV_AttachDspFuncHook,
  196.                MUIA_NList_Format,             "BAR,BAR,",
  197.             End,
  198.          End,
  199.          Child, ColGroup(3),
  200.             Child, bt_okay = MakeButton(yestext),
  201.             Child, HSpace(0),
  202.             Child, bt_cancel = MakeButton(notext),
  203.          End,
  204.       End,
  205.    End;
  206.    if (wi_ar)
  207.    {
  208.       static struct Part spart[2];
  209.       spart[0].Nr = -2; strcpy(spart[0].Name, GetStr(MSG_RE_Original)); spart[0].Size = G->RE[winnum]->Mail.Size; spart[0].Decoded = TRUE;
  210.       spart[1].Nr = -1; strcpy(spart[1].Name, GetStr(MSG_RE_AllTexts)); spart[1].Size = 0;
  211.       DoMethod(lv_attach, MUIM_NList_InsertSingle, &spart[0], MUIV_NList_Insert_Bottom);
  212.       if ((mode&0xF) != ATTREQ_DISP) DoMethod(lv_attach, MUIM_NList_InsertSingle, &spart[1], MUIV_NList_Insert_Bottom);
  213.       for (part = G->RE[winnum]->FirstPart->Next; part; part = part->Next)
  214.          if ((mode&0xF) != ATTREQ_PRINT || part->Printable) DoMethod(lv_attach, MUIM_NList_InsertSingle, part, MUIV_NList_Insert_Bottom);
  215. //      set(lv_attach, MUIA_NList_Active, 1);
  216.       set(wi_ar, MUIA_Window_ActiveObject, lv_attach);
  217.       set(G->App, MUIA_Application_Sleep, TRUE);
  218.       DoMethod(G->App, OM_ADDMEMBER, wi_ar);
  219.       DoMethod(bt_okay  , MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 1);
  220.       DoMethod(bt_cancel, MUIM_Notify, MUIA_Pressed, FALSE, G->App, 2, MUIM_Application_ReturnID, 3);
  221.       DoMethod(lv_attach, MUIM_Notify, MUIA_NList_DoubleClick, MUIV_EveryTime, G->App, 2, MUIM_Application_ReturnID, 1);
  222.       DoMethod(wi_ar, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, G->App, 2, MUIM_Application_ReturnID, 3);
  223.       if (!SafeOpenWindow(wi_ar)) retpart = NULL;
  224.       else  while (retpart == (struct Part *)-1)
  225.       {
  226.          ULONG signals;
  227.          int id;
  228.          switch (DoMethod(G->App, MUIM_Application_Input, &signals))
  229.          {
  230.             case 1:
  231.                for (id = MUIV_NList_NextSelected_Start;; prevpart = part)
  232.                {
  233.                   DoMethod(lv_attach, MUIM_NList_NextSelected, &id);
  234.                   if (id == MUIV_NList_NextSelected_End) break;
  235.                   DoMethod(lv_attach, MUIM_NList_GetEntry, id, &part);
  236.                   if (retpart == (struct Part *)-1) retpart = part;
  237.                   else prevpart->NextSelected = part;
  238.                }
  239.                break;
  240.             case 3: retpart = NULL; break;
  241.          }
  242.          if (retpart == (struct Part *)-1 && signals) Wait(signals);
  243.       }
  244.       DoMethod(G->App, OM_REMMEMBER, wi_ar);
  245.       set(G->App, MUIA_Application_Sleep, FALSE);
  246.    }
  247.    return retpart;
  248. }
  249. ///
  250. /// InfoWindow
  251. //  Displays a text in an own window
  252. void InfoWindow(char *title, char *body, char *oktext, APTR parent)
  253. {
  254.    APTR bt_okay, wi_iw;
  255.  
  256.    if ((wi_iw = WindowObject,
  257.          MUIA_Window_Title, title,
  258.          MUIA_Window_RefWindow, parent,
  259.          MUIA_Window_LeftEdge, MUIV_Window_LeftEdge_Centered,
  260.          MUIA_Window_TopEdge, MUIV_Window_TopEdge_Centered,
  261.          WindowContents, VGroup,
  262.             MUIA_Background, MUII_RequesterBack,
  263.             Child, VGroup,
  264.                TextFrame,
  265.                MUIA_Background, MUII_TextBack,
  266.                Child, LLabel(body),
  267.             End,
  268.             Child, HCenter(bt_okay = MakeButton(oktext)),
  269.          End,
  270.       End))
  271.    {
  272.       DoMethod(G->App, OM_ADDMEMBER, wi_iw);
  273.       DoMethod(bt_okay, MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 5, MUIM_Application_PushMethod, parent, 2, MUIM_MainWindow_CloseWindow, wi_iw);
  274.       DoMethod(wi_iw  , MUIM_Notify, MUIA_Window_CloseRequest, TRUE, MUIV_Notify_Application, 5, MUIM_Application_PushMethod, parent, 2, MUIM_MainWindow_CloseWindow, wi_iw);
  275.       set(wi_iw, MUIA_Window_DefaultObject, bt_okay);
  276.       set(wi_iw, MUIA_Window_Open, TRUE);
  277.    }
  278. }
  279. ///
  280.  
  281. /*** String related ***/
  282. /// itoa
  283. //  Converts an integer into a string
  284. char *itoa(int val)
  285. {
  286.    static char str[SIZE_SMALL];
  287.    sprintf(str, "%ld", val);
  288.    return str;
  289. }
  290. ///
  291. /// MatchNoCase
  292. //  Case insensitive pattern matching
  293. int MatchNoCase(char *string, char *match)
  294. {
  295.    char pattern[SIZE_PATTERN];
  296.    ParsePatternNoCase(match, pattern, SIZE_PATTERN);
  297.    return MatchPatternNoCase(pattern, string);
  298. }
  299. ///
  300. /// CompNoCase
  301. //  Case insensitive string comparison
  302. BOOL CompNoCase(char *a, char *b, int l)
  303. {
  304.    for (; l; l--, a++, b++) if (toupper(*a) != toupper(*b)) return FALSE;
  305.    return TRUE;
  306. }
  307. ///
  308. /// MatchTT
  309. //  Checks if charset matches a translation table
  310. BOOL MatchTT(char *charset, struct TranslationTable *tt, BOOL in)
  311. {
  312.    if (!tt) return FALSE;
  313.    return (BOOL)MatchNoCase(charset, in ? tt->SourceCharset : tt->DestCharset);
  314. }
  315. ////
  316. /// ISpace
  317. //  Checks if character is a white-space
  318. BOOL ISpace(char ch)
  319. {
  320.    return (BOOL)(ch == ' ' || (ch >= 9 && ch <= 13));
  321. }
  322. ///
  323. /// isSpace
  324. //  Localized version if isspace()
  325. BOOL isSpace(int c)
  326. {
  327.    UBYTE ch = (UBYTE)c;
  328.    return (BOOL)(G->Locale ? (IsSpace(G->Locale,(ULONG)ch) != 0) : (isspace(ch) != 0));
  329. }
  330. ///
  331. /// isGraph
  332. //  Localized version of isgraph()
  333. BOOL isGraph(int c)
  334. {
  335.    UBYTE ch = (UBYTE)c;
  336.    return (BOOL)(G->Locale ? (IsGraph(G->Locale,(ULONG)ch) != 0) : (isgraph(ch) != 0));
  337. }
  338. ///
  339. /// isAlNum
  340. //  Localized version of isalnum()
  341. BOOL isAlNum(int c)
  342. {
  343.    UBYTE ch = (UBYTE)c;
  344.    return (BOOL)(G->Locale ? (IsAlNum(G->Locale,(ULONG)ch) != 0) : (isalnum(ch) != 0));
  345. }
  346. ///
  347. /// StripUnderscore
  348. //  Removes underscore from button labels
  349. char *StripUnderscore(char *label)
  350. {
  351.    if (strchr(label,'_'))
  352.    {
  353.       static char newlabel[SIZE_DEFAULT];
  354.       char *p = newlabel;
  355.       for (; *label; label++) if (*label != '_') *p++ = *label;
  356.       *p = 0;
  357.       return newlabel;
  358.    }
  359.    else return label;
  360. }
  361. ///
  362. /// GetNextLine
  363. //  Reads next line from a multi-line string
  364. char *GetNextLine(char *p1)
  365. {
  366.    static char *begin;
  367.    char *p2;
  368.    if (p1) begin = p1;
  369.    if ((p1 = strchr(p2 = begin, '\n'))) { *p1 = 0; begin = ++p1; }
  370.    return p2;
  371. }
  372. ///
  373. /// TrimStart
  374. //  Strips leading spaces
  375. char *TrimStart(char *s)
  376. {
  377.    while (*s && ISpace(*s)) ++s;
  378.    return s;
  379. }       
  380. ///
  381. /// TrimEnd
  382. //  Removes trailing spaces
  383. char *TrimEnd(char *s)
  384. {
  385.    char *e = s+strlen(s)-1;
  386.    while (e >= s && ISpace(*e)) *e-- = 0;
  387.    return s;
  388. }
  389. ///
  390. /// Trim
  391. //  Removes leading and trailing spaces
  392. char *Trim(char *s)
  393. {
  394.    char *e = s+strlen(s)-1;
  395.    while (*s && ISpace(*s)) ++s;
  396.    while (e >= s && ISpace(*e)) *e-- = 0;
  397.    return s;
  398. }       
  399. ///
  400. /// stccat
  401. //  Safe string concatenation
  402. char *stccat(char *a, char *b, int n)
  403. {
  404.    int m = 1;
  405.    char *p = a;
  406.    while (*p) { p++; m++; }
  407.    while (*b && m < n) { *p++ = *b++; m++; }
  408.    *p = 0;
  409.    return a;
  410. }
  411. ///
  412. /// stristr
  413. //  Case insensitive version of strstr()
  414. char *stristr(char *a, char *b)
  415. {
  416.    int l = strlen(b);
  417.    for (; *a; a++) if (CompNoCase(a, b, l)) return a;
  418.    return NULL;
  419. }
  420. ///
  421. /// MyStrChr
  422. //  Searches for a character in string, ignoring text in quotes
  423. char *MyStrChr(char *s, int c)
  424. {
  425.    BOOL nested = FALSE;
  426.    for (; *s; s++)
  427.       if (*s == '\"') nested = !nested; 
  428.       else if (*s == (char)c && !nested) return s;
  429.    return NULL;
  430. }
  431. ///
  432. /// Index
  433. //  Returns position of a character in a string
  434. int Index(char *str, char chr)
  435. {
  436.    char *t = strchr(str, chr);
  437.    return t ? (int)(t-str) : -1;
  438. }
  439. ///
  440. /// AllocStrBuf
  441. //  Allocates a dynamic buffer
  442. char *AllocStrBuf(long initlen)
  443. {
  444. //   char *strbuf = AllocMem(initlen+4, MEMF_PUBLIC|MEMF_CLEAR);
  445.    char *strbuf = calloc(initlen+4,1);
  446.    if (strbuf)
  447.    {
  448.       *((long *)strbuf) = initlen;
  449.       return &strbuf[4];
  450.    }
  451.    return NULL;
  452. }
  453. ///
  454. /// FreeStrBuf
  455. //  Frees a dynamic buffer
  456. void FreeStrBuf(char *strbuf)
  457. {
  458.    long len;
  459.  
  460.    if (!strbuf) return;
  461.    len = *((long *)(strbuf-4));
  462. //   FreeMem(strbuf-4, len+4);
  463.    free(strbuf-4);
  464. }
  465. ///
  466. /// StrBufCpy
  467. //  Fills a dynamic buffer
  468. char *StrBufCpy(char *strbuf, char *source)
  469. {
  470.    long oldlen, newlen;
  471.    char *newstrbuf;
  472.  
  473.    if (!strbuf)
  474.         if(NULL == (strbuf = AllocStrBuf(strlen(source)+1))) return NULL;
  475.    oldlen = *((long *)(strbuf-sizeof(long)));
  476.    newstrbuf = strbuf;
  477.    for (newlen = oldlen; newlen <= strlen(source); newlen += SIZE_DEFAULT);
  478.    if (newlen != oldlen)
  479.    {
  480.       FreeStrBuf(strbuf);
  481.       newstrbuf = AllocStrBuf(newlen);
  482.    }
  483.    if(newstrbuf) strcpy(newstrbuf, source);
  484.    return newstrbuf;
  485. }
  486. ///
  487. /// StrBufCat
  488. //  String concatenation using a dynamic buffer
  489. char *StrBufCat(char *strbuf, char *source)
  490. {
  491.    long oldlen, newlen;
  492.    char *newstrbuf;
  493.  
  494.    if (!strbuf)
  495.         if(NULL == (strbuf = AllocStrBuf(strlen(source)+1))) return NULL;
  496.    oldlen = *((long *)(strbuf-sizeof(long)));
  497.    newstrbuf = strbuf;
  498.    for (newlen = oldlen; newlen <= strlen(strbuf)+strlen(source); newlen += SIZE_DEFAULT);
  499.    if (newlen != oldlen)
  500.    {
  501.       if(NULL == (newstrbuf = AllocStrBuf(newlen)))
  502.       {
  503.             FreeStrBuf(strbuf);
  504.             return NULL;
  505.         }
  506.       strcpy(newstrbuf, strbuf);
  507.       FreeStrBuf(strbuf);
  508.    }
  509.    strcat(newstrbuf, source);
  510.    return newstrbuf;
  511. }
  512. ///
  513. /// FreeData2D
  514. //  Frees dynamic two-dimensional array
  515. void FreeData2D(struct Data2D *data)
  516. {
  517.    while (data->Used) FreeStrBuf(data->Data[--data->Used]);
  518.    if (data->Allocated) free(data->Data);
  519.    data->Data = NULL; data->Allocated = 0;
  520. }
  521. ///
  522. /// AllocData2D
  523. //  Allocates dynamic two-dimensional array
  524. char *AllocData2D(struct Data2D *data, int initsize)
  525. {
  526.    if (data->Used >= data->Allocated)
  527.    {
  528.       data->Allocated += 10;
  529.       if (data->Data) data->Data = realloc(data->Data, data->Allocated*sizeof(char *));
  530.       else            data->Data = malloc(data->Allocated*sizeof(char *));
  531.    }
  532.    return data->Data[data->Used++] = AllocStrBuf(initsize);
  533. }
  534. ///
  535. /// AllocCopy
  536. //  Duplicates a memory block
  537. APTR AllocCopy(APTR source, int size)
  538. {
  539.    APTR dest;
  540.    if ((dest = malloc(size))) memcpy(dest, source, size);
  541.    return dest;
  542. }
  543. ///
  544. /// Decrypt
  545. //  Decrypts passwords
  546. char *Decrypt(char *source)
  547. {
  548.    static char buffer[SIZE_PASSWORD+2];
  549.    char *write = &buffer[SIZE_PASSWORD];
  550.  
  551.    *write-- = 0;
  552.    while (*source)
  553.    {
  554.       *write-- = ((char)atoi(source))^CRYPTBYTE;
  555.       source += 4;
  556.    }
  557.    return ++write;
  558. }
  559. ///
  560. /// Encrypt
  561. //  Encrypts passwords
  562. char *Encrypt(char *source)
  563. {
  564.    static char buffer[4*SIZE_PASSWORD+2];
  565.    char *read = source+strlen(source)-1;
  566.  
  567.    *buffer = 0;
  568.    while (read >= source)
  569.    {
  570.       unsigned char c = (*read--)^CRYPTBYTE;
  571.       sprintf(&buffer[strlen(buffer)], "%03d ", c);
  572.    }
  573.    return buffer;
  574. }
  575. ///
  576.  
  577. /*** File related ***/
  578. /// GetLine
  579. //  Gets Null terminated line of a text file
  580. char *GetLine(FILE *fh, char *buffer, int bufsize)
  581. {
  582.    char *ptr;
  583.    clear(buffer, bufsize);
  584.    if (!fgets(buffer, bufsize, fh)) return NULL;
  585.    if ((ptr = strpbrk(buffer, "\r\n"))) *ptr = 0;
  586.    return buffer;
  587. }       
  588. ///
  589. /// FileInfo
  590. //  Gets size, protection bits and type of a file/directory
  591. BOOL FileInfo(char *filename, int *size, long *bits, long *type)
  592. {
  593.    struct FileInfoBlock *fib;
  594.    BPTR lock;
  595.  
  596.    if ((lock = Lock((STRPTR)filename,ACCESS_READ)))
  597.    {
  598.       fib = AllocDosObject(DOS_FIB, NULL);
  599.       Examine(lock, fib);
  600.       if (size) *size = fib->fib_Size;
  601.       if (bits) *bits = fib->fib_Protection;
  602.       if (type) *type = fib->fib_DirEntryType;
  603.       FreeDosObject(DOS_FIB, fib);
  604.       UnLock(lock);
  605.       return TRUE;
  606.    }
  607.    return FALSE;
  608. }
  609. ///
  610. /// FileSize
  611. //  Returns size of a file
  612. int FileSize(char *filename)
  613. {
  614.    int size;
  615.    if (FileInfo(filename, &size, NULL, NULL)) return size; else return -1;
  616. }
  617. ///
  618. /// FileProtection
  619. //  Returns protection bits of a file
  620. long FileProtection(char *filename)
  621. {
  622.    long bits;
  623.    if (FileInfo(filename, NULL, &bits, NULL)) return bits; else return -1;
  624. }
  625. ///
  626. /// FileType
  627. //  Returns file type (file/directory)
  628. int FileType(char *filename)
  629. {
  630.    long type;
  631.    if (FileInfo(filename, NULL, NULL, &type)) return (type < 0 ? 1 : 2); else return 0;
  632. }
  633. ///
  634. /// FileExists
  635. //  Checks if a file exists
  636. BOOL FileExists(char *filename)
  637. {
  638.    return FileInfo(filename, NULL, NULL, NULL);
  639. }
  640. ///
  641. /// RenameFile
  642. //  Renames a file and restores the protection bits
  643. BOOL RenameFile(char *oldname, char *newname)
  644. {
  645.    struct FileInfoBlock *fib;
  646.    BPTR lock;
  647.    if (!Rename(oldname, newname)) return FALSE;
  648.    if((fib = AllocDosObject(DOS_FIB,NULL)))
  649.     {
  650.        if ((lock = Lock(newname, ACCESS_READ)))
  651.        {
  652.           Examine(lock, fib); UnLock(lock);
  653.           SetProtection(newname, fib->fib_Protection & (~FIBF_ARCHIVE));
  654.        }
  655.        FreeDosObject(DOS_FIB,fib);
  656.     } else return FALSE;
  657.    return TRUE;
  658. }
  659. ///
  660. /// CopyFile
  661. //  Copies a file
  662. BOOL CopyFile(char *dest, FILE *destfh, char *sour, FILE *sourfh)
  663. {
  664.    BOOL success = FALSE;
  665.  
  666.    if (sour) sourfh = fopen(sour, "r");
  667.    if (dest) destfh = fopen(dest, "w");
  668.    if (sourfh && destfh)
  669.    {
  670.       char buf[SIZE_LARGE];
  671.       int len;
  672.       success = TRUE;
  673.       while ((len = fread(buf, 1, SIZE_LARGE, sourfh)))
  674.          if (fwrite(buf, 1, len, destfh) != len) { success = FALSE; break; }
  675.    }
  676.    if (dest && destfh) fclose(destfh);
  677.    if (sour && sourfh) fclose(sourfh);
  678.    return success;
  679. }
  680. ///
  681. /// ConvertCRLF
  682. //  Converts line breaks from LF to CRLF or vice versa
  683. BOOL ConvertCRLF(char *in, char *out, BOOL to)
  684. {
  685.    BOOL success = FALSE;
  686.    char buf[SIZE_LINE];
  687.    FILE *infh, *outfh;
  688.  
  689.    if ((infh = fopen(in, "r")))
  690.    {
  691.       if ((outfh = fopen(out, "w")))
  692.       {
  693.          while (GetLine(infh, buf, SIZE_LINE)) fprintf(outfh, "%s%s\n", buf, to?"\r":"");
  694.          success = TRUE;
  695.          fclose(outfh);
  696.       }
  697.       fclose(infh);
  698.    }
  699.    return success;
  700. }
  701. ///
  702. /// GetWord
  703. //  Word-wrapping algorithm: gets next word
  704. LOCAL int GetWord(char **rptr, char *wbuf, int max)
  705. {
  706.    int c, i = 0;
  707.    static int nonblanks = 0;
  708.  
  709.    if (!(c = *(*rptr)++)) { *wbuf = 0; return 0; }
  710.    if (isSpace(c))
  711.    {
  712.       while (isSpace(c) && c != '\n')
  713.       {
  714.          if (i < max-1) wbuf[i++] = c;
  715.          c = *(*rptr)++;
  716.       }
  717.       if (c == '\n' || !c) { i = 0; wbuf[i++] = '\n'; }
  718.    }
  719.    else
  720.    {
  721.       while (isGraph(c))
  722.       {
  723.          if (i < max-1) wbuf[i++] = c; else break;
  724.          c = *(*rptr)++;
  725.       }
  726.       nonblanks += i;
  727.       while (isSpace(c) && c != '\n') c = *(*rptr)++;
  728.       if (c == '\n')
  729.       {
  730.          if (nonblanks <= 20) wbuf[i++] = '\n';
  731.          nonblanks = 0;
  732.       }
  733.    }
  734.    if (isGraph(c)) (*rptr)--;
  735.    wbuf[i] = '\0'; return i;
  736. }
  737. ///
  738. /// ReflowParagraph
  739. //  Word-wrapping algorithm: process a paragraph
  740. LOCAL char *ReflowParagraph(char *start, char *end, int lmax, char *dest)
  741. {
  742.    int lword, lline = 0;
  743.    char c, word[SIZE_LARGE], *p;
  744.    BOOL dented = FALSE;
  745.  
  746.    while ((lword = GetWord(&start, word, SIZE_LARGE)))
  747.    {
  748.       if ((c = word[lword-1]) == '\n')  word[--lword] = '\0';
  749.       if (!lword);
  750.       else if (isSpace(*word))
  751.       {
  752.          if (lline) *dest++ = '\n';
  753.          dented = TRUE; lline = lword;
  754.          for (p = word; *p; p++) *dest++ = *p;
  755.       }
  756.       else
  757.       {
  758.          if (lline == 0 || dented) { for (p = word; *p; p++) *dest++ = *p; lline += lword; dented = FALSE; }
  759.          else
  760.          {
  761.             if (lline+lword < lmax) { *dest++ = ' '; for (p = word; *p; p++) *dest++ = *p; lline += lword+1; }
  762.             else { *dest++ = '\n'; for (p = word; *p; p++) *dest++ = *p; lline = lword; }
  763.          }
  764.       }
  765.       if (c == '\n') { *dest++ = '\n'; lline = 0; }
  766.       if (start > end) break;
  767.    }
  768.    if (lline) *dest++ = '\n';
  769.    *dest-- = 0;
  770.    return dest;
  771. }
  772. ///
  773. /// RemoveQuoteString
  774. //  Removes reply prefix
  775. LOCAL char *RemoveQuoteString(char *start, char *end, char *quot, char *dest)
  776. {
  777.    while (start <= end)
  778.    {
  779.       if (!strncmp(start, quot, strlen(quot))) start += strlen(quot);
  780.       while (*start && *start != '\n') *dest++ = *start++;
  781.       if (*start) *dest++ = *start++;
  782.    }
  783.    *dest-- = 0;
  784.    return dest;
  785. }
  786. ///
  787. /// InsertQuoteString
  788. //  Inserts reply prefix
  789. LOCAL char *InsertQuoteString(char *start, char *quote, FILE *out)
  790. {
  791.    if ((*start != '\n' || C->QuoteEmptyLines) && strncmp(start, "<sb>", 4) && strncmp(start, "<tsb>", 5))
  792.    {
  793.       int level, i;
  794.       for (i = level = 0; start[i] && start[i] != '\n' && i < 16; i++)
  795.       {
  796.          if (isSpace(start[i]) && (!level || start[i+1] == '>')) continue;
  797.          if (start[i] == '>') level++; else if (!isAlNum(start[i]) || level) break;
  798.       }
  799.       if (level) start = &start[i];
  800.       if (level > 8) level = 8;
  801.       fputs(quote, out); while (level--) fputc('>', out);
  802.       if (*start != ' ') fputc(' ', out);
  803.    }
  804.    return start;
  805. }
  806. ///
  807. /// SaveParagraph
  808. //  Writes a paragraph and inserts reply prefixes
  809. LOCAL void SaveParagraph(char *start, char *end, char *prefix, FILE *out)
  810. {
  811.    while (start <= end)
  812.    {
  813.       if (*prefix) start = InsertQuoteString(start, prefix, out);
  814.       while (*start && *start != '\n') fputc(*start++, out);
  815.       if (*start) fputc(*start++, out);
  816.    }
  817. }
  818. ///
  819. /// QuoteWordWrap
  820. //  Reformats quoted messages to a new line length
  821. void QuoteWordWrap(char *rptr, int lmax, char *prefix, char *firstprefix, FILE *out)
  822. {
  823.    if (!prefix) prefix = firstprefix;
  824.    while (*rptr)
  825.    {
  826.       char *p, *ps = rptr, *pe, quot[17], c;
  827.       int lsm = 0;
  828.       *quot = 0;
  829.       while (TRUE)
  830.       {
  831.          int ls = 0;
  832.          char *p = rptr;
  833.          while (*rptr && *rptr != '\n') { rptr++; ls++; }
  834.          if (ls && *p == '>' && !*quot)
  835.          {
  836.             int i = 0;
  837.             while ((*p == ' ' || *p == '>') && i < 16) quot[i++] = *p++;
  838.             quot[i] = 0;
  839.             while (i > 1) if (quot[i-2] == ' ' && quot[i-1] == ' ') quot[--i] = 0; else break;
  840.          }
  841.          if (ls > lsm) lsm = ls;
  842.          if (!*rptr) break;
  843.          c = rptr[1];
  844.          if (isSpace(c) || !c || c == '\n') break;
  845.          if (!*quot && c == '>') break;
  846.          if (*quot) if (strncmp(&rptr[1], quot, strlen(quot))) break;
  847.          rptr++;
  848.       }
  849.       pe = rptr;
  850.       if (lsm > lmax)
  851.       {
  852.          if (*quot)
  853.          {
  854.             char *buf = calloc(2*(pe-ps+2),1), newprefix[SIZE_DEFAULT];
  855.             RemoveQuoteString(ps, pe, quot, buf);
  856.             strcpy(newprefix, firstprefix); strcat(newprefix, TrimEnd(quot));
  857.             QuoteWordWrap(buf, lmax-strlen(quot), newprefix, firstprefix, out);
  858.             free(buf);
  859.          }
  860.          else
  861.          {
  862.             char *buf = calloc(2*(pe-ps+2),1);
  863.             p = ReflowParagraph(ps, pe, lmax, buf);
  864.             SaveParagraph(buf, p, prefix, out);
  865.             free(buf);
  866.          }
  867.       }
  868.       else SaveParagraph(ps, pe, prefix, out);
  869.       rptr = pe+1;
  870.    }
  871. }
  872. ///
  873. /// SimpleWordWrap
  874. //  Reformats a file to a new line length
  875. void SimpleWordWrap(char *filename, int wrapsize)
  876. {
  877.    BPTR fh;
  878.    if ((fh = Open((STRPTR)filename, MODE_OLDFILE)))
  879.    {
  880.       char ch;
  881.       int p = 0, lsp = -1, sol = 0;
  882.  
  883.       while (Read(fh, &ch, 1))
  884.       {
  885.          if (p-sol > wrapsize && lsp >= 0) 
  886.          {
  887.             ch = '\n';
  888.             Seek(fh, lsp-p-1, OFFSET_CURRENT);
  889.             p = lsp;
  890.             Write(fh, &ch, 1);
  891.          }
  892.          if (ISpace(ch)) lsp = p;
  893.          if (ch == '\n') { sol = p+1; lsp = -1; }
  894.          p++;
  895.       }
  896.       Close(fh);
  897.    }
  898. }
  899. ///
  900. /// ReqFile
  901. //  Puts up a file requester
  902. int ReqFile(int num, struct Object *win, char *title, int mode, char *drawer, char *file)
  903. {   
  904.    static BOOL init[MAXASL] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE };
  905.    static char *pattern[MAXASL] =  { "#?.addressbook#?", "#?.config#?", NULL, NULL, "#?.(yam|rexx)", "#?.(gif|jpg|jpeg|png|iff|ilbm)", NULL, NULL };
  906.    struct Window *truewin;
  907.    int skip = *file ? 1 : 2;
  908.    char *postext = (mode & 1)==1 ? GetStr(MSG_UT_Save) : GetStr(MSG_UT_Load);
  909.  
  910.    get(win, MUIA_Window_Window, &truewin);
  911.    if (!init[num]) { init[num] = TRUE; skip = 0; }
  912.    return MUI_AslRequestTags(G->ASLReq[num],
  913.       ASLFR_Window, truewin,
  914.       ASLFR_TitleText, title,
  915.       ASLFR_PositiveText, postext,
  916.       ASLFR_InitialFile, file,
  917.       ASLFR_DoSaveMode, (mode & 1)==1,
  918.       ASLFR_DoMultiSelect, (mode & 2)==2,
  919.       ASLFR_DrawersOnly, (mode & 4)==4,
  920.       ASLFR_DoPatterns, pattern[num] != NULL,
  921.       skip ? TAG_DONE : ASLFR_InitialDrawer, drawer,
  922.       ASLFR_InitialPattern, pattern[num] ? pattern[num] : "#?",
  923.       TAG_DONE);
  924. }
  925. ///
  926. /// OpenTempFile
  927. //  Creates or opens a temporary file
  928. struct TempFile *OpenTempFile(char *mode)
  929. {
  930.    static int count = 0;
  931.    struct TempFile *tf;
  932.    if ((tf = calloc(1, sizeof(struct TempFile))))
  933.    {
  934.       char buf[SIZE_SMALL];
  935.       sprintf(buf, "YAM.%ld.tmp", ++count);
  936.       strmfp(tf->Filename, C->TempDir, buf);
  937.       if (!mode) return tf;
  938.       if ((tf->FP = fopen(tf->Filename, mode))) return tf;
  939.       free(tf);
  940.    }
  941.    return NULL;
  942. }
  943. ///
  944. /// CloseTempFile
  945. //  Closes a temporary file
  946. void CloseTempFile(struct TempFile *tf)
  947. {
  948.    if (tf)
  949.    {
  950.       if (tf->FP) fclose(tf->FP);
  951.       DeleteFile(tf->Filename);
  952.       free(tf);
  953.    }
  954. }
  955. ///
  956. /// DumpClipboard
  957. //  Exports contents of clipboard unit 0 to a file
  958. #define ID_FTXT   MAKE_ID('F','T','X','T')
  959. #define ID_CHRS   MAKE_ID('C','H','R','S')
  960. BOOL DumpClipboard(FILE *out)
  961. {
  962.    struct IFFHandle *iff;
  963.    struct ContextNode *cn;
  964.    long   error, rlen;
  965.    UBYTE  readbuf[SIZE_DEFAULT];
  966.    BOOL   success = FALSE;
  967.  
  968.    if ((iff = AllocIFF()))
  969.    {
  970.       if ((iff->iff_Stream = (ULONG)OpenClipboard(PRIMARY_CLIP)))
  971.       {
  972.          InitIFFasClip(iff);
  973.          if (!OpenIFF(iff, IFFF_READ))
  974.          {
  975.             if (!StopChunk(iff, ID_FTXT, ID_CHRS)) while (TRUE)
  976.             {
  977.                error = ParseIFF(iff, IFFPARSE_SCAN);
  978.                if (error == IFFERR_EOC) continue; else if (error) break;
  979.                cn = CurrentChunk(iff);
  980.                if (cn) if (cn->cn_Type == ID_FTXT && cn->cn_ID == ID_CHRS)
  981.                {
  982.                   success = TRUE;
  983.                   while ((rlen = ReadChunkBytes(iff, readbuf, SIZE_DEFAULT)) > 0)
  984.                      fwrite(readbuf, 1, rlen, out);
  985.                }
  986.             }
  987.             CloseIFF(iff);
  988.          }
  989.          CloseClipboard((struct ClipboardHandle *)iff->iff_Stream);
  990.       }
  991.       FreeIFF(iff);
  992.    }
  993.    return success;
  994. }
  995. ///
  996. /// IsFolderDir
  997. //  Checks if a directory is used as a mail folder
  998. BOOL IsFolderDir(char *dir)
  999. {
  1000.    char *filename = FilePart(dir);
  1001.    int i;
  1002.    for (i = 0; i < 4; i++) if (!stricmp(filename, FolderNames[i])) return TRUE;
  1003.    return (BOOL)(PFExists(dir, ".fconfig") || PFExists(dir, ".index"));
  1004. }
  1005. ///
  1006. /// PFExists
  1007. //  Checks if a file exists in the specified directory
  1008. BOOL PFExists(char *path, char *file)
  1009. {
  1010.    char fname[SIZE_PATHFILE];
  1011.    strmfp(fname, path, file);
  1012.    return (BOOL)(FileSize(fname) >= 0);
  1013. }
  1014. ///
  1015. /// DeleteMailDir
  1016. //  Recursively deletes a mail directory
  1017. void DeleteMailDir(char *dir, BOOL isroot)
  1018. {
  1019.    BOOL cont, isdir;
  1020.    struct FileInfoBlock *fib;
  1021.    BPTR lock;
  1022.    char fname[SIZE_PATHFILE], *filename, dirname[SIZE_PATHFILE];
  1023.  
  1024.    fib = AllocDosObject(DOS_FIB,NULL);
  1025.    if ((lock = Lock(dir, ACCESS_READ)))
  1026.    {
  1027.       strcpy(dirname, dir);
  1028.       Examine(lock, fib);
  1029.       cont = (ExNext(lock,fib) && IoErr() != ERROR_NO_MORE_ENTRIES);
  1030.       while (cont)
  1031.       {
  1032.          strmfp(fname, dir, fib->fib_FileName);
  1033.          filename = FilePart(fname);
  1034.          isdir = fib->fib_DirEntryType > 0;
  1035.          cont = (ExNext(lock,fib) && IoErr() != ERROR_NO_MORE_ENTRIES);
  1036.          if (isroot)
  1037.          {
  1038.             if (isdir)
  1039.             {
  1040.                if (IsFolderDir(fname)) DeleteMailDir(fname, FALSE);
  1041.             }
  1042.             else
  1043.             {
  1044.                if (!stricmp(filename, ".config") || !stricmp(filename, ".glossary") || !stricmp(filename, ".addressbook")) DeleteFile(fname);
  1045.             }
  1046.          }
  1047.          else if (!isdir) if (!stricmp(filename, ".fconfig") || !stricmp(filename, ".index") || IsValidMailFile(filename)) DeleteFile(fname);
  1048.       }
  1049.       UnLock(lock);
  1050.       DeleteFile(dirname);
  1051.    }
  1052.    FreeDosObject(DOS_FIB,fib);
  1053. }
  1054. ///
  1055. /// FileToBuffer
  1056. //  Reads a complete file into memory
  1057. LOCAL char *FileToBuffer(char *file)
  1058. {
  1059.    char *text;
  1060.    int size = FileSize(file);
  1061.    FILE *fh;
  1062.  
  1063.    if (size >= 0) if ((text = calloc(size+1,1)))
  1064.    {
  1065.       if ((fh = fopen(file, "r")))
  1066.       {
  1067.          fread(text, 1, size, fh);
  1068.          fclose(fh);
  1069.          return text;
  1070.       }
  1071.       free(text);
  1072.    }
  1073.    return NULL;
  1074. }
  1075. ///
  1076.  
  1077. /*** Mail related ***/
  1078. /// MyAddTail
  1079. //  Adds a message to a message list
  1080. void MyAddTail(struct Mail **list, struct Mail *new)
  1081. {
  1082.    struct Mail *mail;
  1083.    new->Next = NULL;
  1084.    if (!*list) { *list = new; return; }
  1085.    for (mail = *list; mail->Next; mail = mail->Next);
  1086.    mail->Next = new;
  1087. }
  1088. ///
  1089. /// MyRemove
  1090. //  Removes a message from a message list
  1091. void MyRemove(struct Mail **list, struct Mail *rem)
  1092. {
  1093.    struct Mail *mail;
  1094.    if (*list == rem) { *list = rem->Next; return; }
  1095.    for (mail = *list; mail->Next; mail = mail->Next)
  1096.       if (mail->Next == rem) { mail->Next = rem->Next; return; }
  1097. }
  1098. ///
  1099. /// WhichLV
  1100. //  Returns pointer to message listview if folder is active
  1101. APTR WhichLV(struct Folder *folder)
  1102. {
  1103.    if (folder == FO_GetCurrentFolder()) return G->MA->GUI.NL_MAILS; else return NULL;
  1104. }
  1105. ///
  1106. /// CreateFilename
  1107. //  Prepends mail directory to a file name
  1108. char *CreateFilename(char *file)
  1109. {
  1110.    static char buffer[SIZE_PATHFILE];
  1111.    strmfp(buffer, G->MA_MailDir, file);
  1112.    return buffer;
  1113. }
  1114. ///
  1115. /// CreateDirectory
  1116. //  Makes a directory
  1117. BOOL CreateDirectory(char *dir)
  1118. {
  1119.    int t = FileType(dir);
  1120.    if (t == 2) return TRUE;
  1121.    if (t == 0)
  1122.    {
  1123.       BPTR fl = CreateDir((STRPTR)dir);
  1124.       if (fl)
  1125.       {
  1126.          UnLock(fl);
  1127.          return TRUE;
  1128.       }
  1129.    }
  1130.    if (G->MA) ER_NewError(GetStr(MSG_ER_CantCreateDir), dir, NULL);
  1131.    return FALSE;
  1132. }
  1133. ///
  1134. /// GetFolderDir
  1135. //  Returns path of a folder directory
  1136. char *GetFolderDir(struct Folder *fo)
  1137. {
  1138.    static char buffer[SIZE_PATH];
  1139.    if (strchr(fo->Path, ':')) return fo->Path;
  1140.    strmfp(buffer, G->MA_MailDir, fo->Path);
  1141.    return buffer;
  1142. }
  1143. ///
  1144. /// GetMailFile
  1145. //  Returns path of a message file
  1146. char *GetMailFile(char *string, struct Folder *folder, struct Mail *mail)
  1147. {
  1148.    static char buffer[SIZE_PATHFILE];
  1149.    if (!folder && mail) folder = mail->Folder;
  1150.    if (!string) string = buffer;
  1151.    strmfp(string, (int)folder <= 0 ? C->TempDir : GetFolderDir(folder), mail->MailFile);
  1152.    return string;
  1153. }
  1154. ///
  1155. /// GetMailInfo
  1156. //  Returns location of a message
  1157. struct MailInfo *GetMailInfo(struct Mail *smail)
  1158. {
  1159.    static struct MailInfo mi;
  1160.    int i;
  1161.    
  1162.    mi.Display = smail->Folder == FO_GetCurrentFolder();
  1163.    mi.Pos = -1;
  1164.    mi.FName = GetMailFile(NULL, smail->Folder, smail);
  1165.    if (mi.Display) for (i=0; mi.Pos == -1; i++)
  1166.    {
  1167.       struct Mail *mail;
  1168.       DoMethod(G->MA->GUI.NL_MAILS, MUIM_NList_GetEntry, i, &mail);
  1169.       if (!mail) break;
  1170.       if (mail == smail) mi.Pos = i;
  1171.    }
  1172.    return &mi;
  1173. }
  1174. ///
  1175. /// GetReturnAddress
  1176. //  Gets return address of a message
  1177. struct Person *GetReturnAddress(struct Mail *mail)
  1178. {
  1179.    if (mail->ReplyTo.Address[0]) return &mail->ReplyTo;
  1180.    return &mail->From;
  1181. }
  1182. ///
  1183. /// BuildAddrName
  1184. //  Creates "Real Name" <E-mail> string
  1185. char *BuildAddrName(char *address, char *name)
  1186. {
  1187.    static char buffer[SIZE_ADDRESS+SIZE_REALNAME+4];
  1188.    char *delim;
  1189.  
  1190.    if (*name)
  1191.    {
  1192.       if (strpbrk(name, ",.()")) delim = "\""; else delim = "";
  1193.       sprintf(buffer, "%s%s%s <%s>", delim, name, delim, address);
  1194.    }
  1195.    else sprintf(buffer, "%s", address);
  1196.    return buffer;
  1197. }
  1198. char *BuildAddrName2(struct Person *pe)
  1199. {
  1200.    return BuildAddrName(pe->Address, pe->RealName);
  1201. }
  1202. ///
  1203. /// ExtractAddress
  1204. //  Extracts e-mail address and real name
  1205. void ExtractAddress(char *line, struct Person *pe)
  1206. {
  1207.    char *p = line, *ra[4], *save = malloc(strlen(line)+1);
  1208.    BOOL found = FALSE;
  1209.  
  1210.    ra[2] = ra[3] = NULL;
  1211.    strcpy(save, line);
  1212.    pe->Address[0] = pe->RealName[0] = 0;
  1213.    while (ISpace(*p)) p++;
  1214.    if ((ra[0] = MyStrChr(p,'<'))) if ((ra[1] = MyStrChr(ra[0],'>')))
  1215.    {
  1216.       *ra[0]++ = 0; *ra[1] = 0;
  1217.       for (ra[2] = p, ra[3] = ra[0]-2; ISpace(*ra[3]) && ra[3] >= ra[2]; ra[3]--) *ra[3] = 0;
  1218.       found = TRUE;
  1219.    }
  1220.    if (!found)
  1221.    {
  1222.       for (ra[1] = ra[0] = p; *ra[1] && *ra[1] != '\t' && *ra[1] != ' ' && *ra[1] != ','; ra[1]++);
  1223.       if ((ra[2] = MyStrChr(ra[1],'('))) if ((ra[3] = MyStrChr(ra[2],')')))
  1224.       {
  1225.          ra[2]++; *ra[3]-- = 0;
  1226.          found = TRUE;
  1227.       }
  1228.       *ra[1] = 0;
  1229.       if (!found) ra[2] = ra[3] = "";
  1230.    }
  1231.    if (*ra[2] == '\"') ra[2]++;
  1232.    if (*ra[3] == '\"' && *(ra[3]-1) != '\\') *ra[3] = 0;
  1233.    stccpy(pe->Address , Trim(ra[0]), SIZE_ADDRESS);
  1234.    stccpy(pe->RealName, Trim(ra[2]), SIZE_REALNAME);
  1235.    strcpy(line, save);
  1236.    free(save);
  1237. }
  1238. ///
  1239. /// CompressMsgID
  1240. //  Creates a compressed version of the message ID
  1241. int CompressMsgID(char *msgid)
  1242. {
  1243.    int i = 0, compr = 0;
  1244.    char *ptr = msgid;
  1245.    while (*ptr) compr += ++i*123*(*ptr++);
  1246.    return compr;
  1247. }
  1248. ///
  1249. /// ExpandText
  1250. //  Replaces variables with values
  1251. char *ExpandText(char *src, struct ExpandTextData *etd)
  1252. {
  1253.    static char chr[2] = { 0,0 };
  1254.    char buf[SIZE_ADDRESS], *p, *p2, *dst = AllocStrBuf(SIZE_DEFAULT);
  1255.    struct DateStamp adate;
  1256.   
  1257.    for (; *src; src++)
  1258.       if (*src == '\\')
  1259.       {
  1260.          src++;
  1261.          switch (*src)
  1262.          {
  1263.             case '\\':  dst = StrBufCat(dst, "\\"); break;
  1264.             case 'n':  dst = StrBufCat(dst, "\n"); break;
  1265.          }
  1266.       }
  1267.       else if (*src == '%' && etd)
  1268.       {
  1269.          if (!etd->OM_Date) etd->OM_Date = DateStamp(&adate);
  1270.          src++;
  1271.          switch (*src)
  1272.          {
  1273.             case 'n': dst = StrBufCat(dst, etd->OS_Name); break;
  1274.             case 'f': stccpy(buf, etd->OS_Name, SIZE_ADDRESS);
  1275.                       if ((p = strchr(buf, ','))) p = Trim(++p);
  1276.                       else { for (p = buf; *p && *p != ' '; p++); *p = 0; p = buf; }
  1277.                       dst = StrBufCat(dst, p); break;
  1278.             case 's': dst = StrBufCat(dst, etd->OM_Subject); break;
  1279.             case 'e': dst = StrBufCat(dst, etd->OS_Address); break;
  1280.             case 'd': dst = StrBufCat(dst, DateStamp2String(etd->OM_Date, DSS_DATE)); break;
  1281.             case 't': dst = StrBufCat(dst, DateStamp2String(etd->OM_Date, DSS_TIME)); break;
  1282.             case 'w': dst = StrBufCat(dst, DateStamp2String(etd->OM_Date, DSS_WEEKDAY)); break;
  1283.             case 'm': dst = StrBufCat(dst, etd->OM_MessageID); break;
  1284.             case 'r': dst = StrBufCat(dst, etd->R_Name); break;
  1285.             case 'v': strcpy(buf, etd->R_Name);
  1286.                       if ((p = strchr(buf, ','))) p = Trim(++p);
  1287.                       else { for (p = buf; *p && *p != ' '; p++); *p = 0; p = buf; }
  1288.                       dst = StrBufCat(dst, p); break;
  1289.             case 'a': dst = StrBufCat(dst, etd->R_Address); break;
  1290.             case 'i': strcpy(buf, etd->OS_Name);
  1291.                       for (p = p2 = &buf[1]; *p; p++)
  1292.                          if (*p == ' ' && p[1] && p[1] != ' ') *p2++ = *++p;
  1293.                       *p2 = 0;
  1294.                       dst = StrBufCat(dst, buf); break;
  1295.             case 'j': strcpy(buf, etd->OS_Name);
  1296.                       for (p2 = &buf[1], p = &buf[strlen(buf)-1]; p > p2; p--)
  1297.                          if (p[-1] == ' ') { *p2++ = *p; break; }
  1298.                       *p2 = 0;
  1299.                       dst = StrBufCat(dst, buf); break;
  1300.             case 'h': if ((p = FileToBuffer(etd->HeaderFile)))
  1301.                       {
  1302.                          dst = StrBufCat(dst, p); free(p);
  1303.                       }
  1304.                       break;
  1305.         }
  1306.       }
  1307.       else
  1308.       {
  1309.          chr[0] = *src;
  1310.          dst = StrBufCat(dst, chr);
  1311.       }
  1312.    return dst;
  1313. }              
  1314. ///
  1315. /// DescribeCT
  1316. //  Returns description of a content type
  1317. char *DescribeCT(char *ct)
  1318. {
  1319.    int i;
  1320.    for (i = 0; i < MAXCTYPE; i++)
  1321.       if (!stricmp(ct, ContType[i])) { ct = GetStr(ContTypeDesc[i]); break; }
  1322.    return ct;
  1323. }
  1324. ///
  1325. /// GetDateStamp
  1326. //  Get number of seconds since 1/1-1978
  1327. time_t GetDateStamp(void)
  1328. {
  1329.     struct DateStamp ds;
  1330.     struct DateStamp *rds;
  1331.  
  1332.     rds = DateStamp(&ds);
  1333.     return (rds->ds_Days*24*60*60 + rds->ds_Minute*60 + rds->ds_Tick/TICKS_PER_SECOND);
  1334. }
  1335. ///
  1336. /// DateStamp2String
  1337. //  Converts a datestamp to a string
  1338. char *DateStamp2String(struct DateStamp *date, int mode)
  1339. {
  1340.    static char resstr[32];
  1341.    char *s, datestr[16], timestr[16], daystr[16];
  1342.    struct DateTime dt;
  1343.    struct DateStamp dsnow;
  1344.    long beat;
  1345.  
  1346.    // if this argument is not set we get the actual time
  1347.    if (!date) date = DateStamp(&dsnow);
  1348.  
  1349.    clear(&dt, sizeof(struct DateTime));
  1350.    dt.dat_Stamp   = *date;
  1351.    dt.dat_Format  = FORMAT_DOS;
  1352.    if (mode == DSS_USDATETIME || mode == DSS_UNIXDATE) dt.dat_Format = FORMAT_USA;
  1353.    dt.dat_StrDate = (STRPTR)datestr;
  1354.    dt.dat_StrTime = (STRPTR)timestr;
  1355.    dt.dat_StrDay  = (STRPTR)daystr;
  1356.    DateToStr(&dt);
  1357.  
  1358.    // strip spaces a.s.o.
  1359.    s = Trim(datestr);
  1360.  
  1361.    switch (mode)
  1362.    {
  1363.       case DSS_UNIXDATE:
  1364.       {
  1365.         int y = atoi(&s[6]);
  1366.  
  1367.                // this is a Y2K patch
  1368.         // if less then 8035 days has passed since 1.1.1978 then we are in the 20th century
  1369.                if (date->ds_Days < 8035) y += 1900;
  1370.         else y += 2000;
  1371.  
  1372.           sprintf(resstr, "%s %s %02ld %s %ld\n", wdays[dt.dat_Stamp.ds_Days%7], months[atoi(s)-1], atoi(&s[3]), timestr, y);
  1373.       }
  1374.       break;
  1375.  
  1376.       case DSS_DATETIME:
  1377.       {
  1378.           timestr[5] = 0;
  1379.         sprintf(resstr, "%s %s", s, timestr);
  1380.       }
  1381.       break;
  1382.  
  1383.       case DSS_DATEBEAT:
  1384.       {
  1385.               // calculate the beat time
  1386.                beat = (((date->ds_Minute-60*C->TimeZone+(C->DaylightSaving?0:60)+1440)%1440)*1000)/1440;
  1387.  
  1388.           sprintf(resstr, "%s @%03ld", s, beat);
  1389.       }
  1390.         break;
  1391.  
  1392.       case DSS_USDATETIME:
  1393.       {
  1394.           sprintf(resstr, "%s %s", s, timestr);
  1395.       }
  1396.       break;
  1397.  
  1398.       case DSS_WEEKDAY:
  1399.       {
  1400.           strcpy(resstr, daystr);
  1401.       }
  1402.       break;
  1403.  
  1404.       case DSS_DATE:
  1405.       {
  1406.           strcpy(resstr, s);
  1407.       }
  1408.       break;
  1409.  
  1410.       case DSS_TIME:
  1411.       {
  1412.           strcpy(resstr, timestr);
  1413.       }
  1414.       break;
  1415.  
  1416.       case DSS_BEAT:
  1417.       {
  1418.               // calculate the beat time
  1419.                beat = (((date->ds_Minute-60*C->TimeZone+(C->DaylightSaving?0:60)+1440)%1440)*1000)/1440;
  1420.  
  1421.           sprintf(resstr, "@%03ld", beat);
  1422.       }
  1423.       break;
  1424.    }
  1425.    return resstr;
  1426. }
  1427. ///
  1428. /// DateStamp2Long
  1429. // Converts a datestamp to a numeric value
  1430. long DateStamp2Long(struct DateStamp *date)
  1431. {
  1432.    char *s, datestr[16];
  1433.    struct DateStamp dsnow;
  1434.    struct DateTime dt;
  1435.    int y;
  1436.  
  1437.    if (!date) date = DateStamp(&dsnow);
  1438.    clear(&dt, sizeof(struct DateTime));
  1439.    dt.dat_Stamp   = *date;
  1440.    dt.dat_Format  = FORMAT_USA;
  1441.    dt.dat_StrDate = (STRPTR)datestr;
  1442.    DateToStr(&dt); s = Trim(datestr);
  1443.  
  1444.      // get the year
  1445.      y = atoi(&s[6]);
  1446.  
  1447.      // this is a Y2K patch
  1448.    // if less then 8035 days has passed since 1.1.1978 then we are in the 20th century
  1449.    if (date->ds_Days < 8035) y += 1900;
  1450.    else y += 2000;
  1451.  
  1452.    return((100*atoi(&s[3])+atoi(s))*10000+y);
  1453. }
  1454. ///
  1455. /// GetTZ
  1456. //  Gets the locale time zone
  1457. char *GetTZ(void)
  1458. {
  1459.    static char tzone[SIZE_SMALL];
  1460.    if (GetVar("YAM_TZ", tzone, SIZE_SMALL, 0) < 0)
  1461.    {
  1462.       int tz, tzd;
  1463.       if (G->Locale) {
  1464.          CloseLocale(G->Locale);
  1465.          G->Locale = OpenLocale(NULL);
  1466.          tz = -G->Locale->loc_GMTOffset/60;
  1467.       }
  1468.       else tz = C->TimeZone;
  1469.       tzd = tz + (C->DaylightSaving ? 1 : 0);
  1470.       if (tz >= 0) sprintf(tzone, "+%02d00", tzd);
  1471.       else         sprintf(tzone, "-%02d00", -tzd);
  1472.    }
  1473.    return tzone;
  1474. }
  1475. ///
  1476. /// TZtoMinutes
  1477. //  Converts time zone into a numeric offset
  1478. LOCAL int TZtoMinutes(char *tzone)
  1479. {
  1480.    int i, tzcorr = 0;
  1481.    static struct TimeZones { char *TZname; int TZcorr; }
  1482.    tzones[] = { "sst",-1100, "pst",-800, "mst",-700, "pdt",-700, "cst",-600,
  1483.       "mdt",-600, "est",-500, "ast",-500, "edt",-400, "wgt",-300, "wgst",-200,
  1484.       "aat",-100, "egt",-100, "egst",0, "gmt",0, "utc",0, "wat",0, "wet",0,
  1485.       "bst",100, "cat",100, "cet",100, "met",100, "west",100, "cest",200,
  1486.       "met dst",200, "eet",200, "ist",200, "sat",200, "ast",300, "eat",300,
  1487.       "eest",300, "idt",300, "msk",300, "adt",400, "msd",300, "gst",400,
  1488.       "smt",400, "ict",400, "hkt",800, "wst",800, "jst",900, "kst",1000,
  1489.       "nzst",1200, "nzdt",1300, NULL,0 };
  1490.  
  1491.    if (tzone[0] == '+') tzcorr = atoi(&tzone[1]);
  1492.    else if (tzone[0] == '-') tzcorr = -atoi(&tzone[1]);
  1493.    else for (i = 0; tzones[i].TZname; i++)
  1494.       if (!strnicmp(tzones[i].TZname, tzone, strlen(tzones[i].TZname)))
  1495.       { tzcorr = tzones[i].TZcorr; break; }
  1496.    tzcorr = (tzcorr/100)*60 + (tzcorr%100);
  1497.    return tzcorr;
  1498. }
  1499. ///
  1500. /// ScanDate
  1501. //  Converts textual date header into datestamp format
  1502. struct DateStamp *ScanDate(char *date)
  1503. {
  1504.    int count = 0, day = 0, mon = 0, year = 0, hour = 0, min = 0, sec = 0;
  1505.    char *tzone = "", *p, tdate[SIZE_SMALL], ttime[SIZE_SMALL];
  1506.    static struct DateTime dt;
  1507.    struct DateStamp *ds = &dt.dat_Stamp;
  1508.  
  1509.    if ((p = strchr(date, ','))) p++; else p = date;
  1510.    while (*p && ISpace(*p)) p++;
  1511.    while ((p = strtok(p, " \t")))
  1512.    {
  1513.       switch (count)
  1514.       {
  1515.          case 0: if (!isdigit(*p)) return NULL;
  1516.                  if ((day = atoi(p)) > 31) return NULL;
  1517.                  break;
  1518.          case 1: for (mon = 1; mon <= 12; mon++) if (!strnicmp(p, months[mon-1], 3)) break;
  1519.                  if (mon > 12) return NULL;
  1520.                  break;
  1521.          case 2: year = atoi(p);
  1522.                  break;
  1523.          case 3: if (sscanf(p, "%d:%d:%d", &hour, &min, &sec) == 3) ;
  1524.                  else if (sscanf (p, "%d:%d", &hour, &min) == 2) sec = 0;
  1525.                  else return NULL;
  1526.                  break;
  1527.          case 4: while (*p && (ISpace(*p) || *p == '(')) p++;
  1528.                  tzone = p;
  1529.                  break;
  1530.       }
  1531.       count++; p = NULL;
  1532.    }
  1533.    sprintf(tdate, "%02ld-%02ld-%02ld", mon, day, year%100);
  1534.    sprintf(ttime, "%02ld:%02ld:%02ld", hour, min, sec);
  1535.    dt.dat_Format  = FORMAT_USA;
  1536.    dt.dat_Flags   = 0;
  1537.    dt.dat_StrDate = (STRPTR)tdate;
  1538.    dt.dat_StrTime = (STRPTR)ttime;
  1539.    StrToDate(&dt);
  1540.    ds->ds_Minute -= TZtoMinutes(tzone);
  1541.    ds->ds_Minute += TZtoMinutes(GetTZ());
  1542.    while (ds->ds_Minute < 0)  { ds->ds_Minute += 1440; ds->ds_Days--; }
  1543.    while (ds->ds_Minute >= 1440) { ds->ds_Minute -= 1440; ds->ds_Days++; }
  1544.    return ds;
  1545. }
  1546. ///
  1547. /// FormatSize
  1548. //  Displays large numbers using group separators
  1549. void FormatSize(int size, char *buffer)
  1550. {
  1551.    char *gs = G->Locale ? (char *)G->Locale->loc_GroupSeparator : ".";
  1552.    char *p = &buffer[strlen(buffer)];
  1553.    if (size >= 1000000) sprintf(p, "%d%s%03d%s%03d", size/1000000, gs, (size%1000000)/1000, gs, size%1000);
  1554.    if (size >= 1000 && size < 1000000) sprintf(p, "%d%s%03d", size/1000, gs, size%1000);
  1555.    if (size < 1000) sprintf(p, "%d", size);
  1556. }
  1557. ///
  1558. /// MailExists
  1559. //  Checks if a message still exists
  1560. BOOL MailExists(struct Mail *mailptr, struct Folder *folder)
  1561. {
  1562.    struct Mail *work;
  1563.    if (Virtual(mailptr)) return TRUE;
  1564.    if (!folder) folder = mailptr->Folder;
  1565.    for (work = folder->Messages; work; work = work->Next) if (work == mailptr) return TRUE;
  1566.    return FALSE;
  1567. }
  1568. ///
  1569. /// SelectMessage
  1570. //  Activates a message in the message listview
  1571. int SelectMessage(struct Mail *mail)
  1572. {
  1573.    struct MailInfo *mi;
  1574.    if (mail->Folder != FO_GetCurrentFolder()) MA_ChangeFolder(mail->Folder);
  1575.    mi = GetMailInfo(mail);
  1576.    if (mi->Pos >= 0) set(G->MA->GUI.NL_MAILS, MUIA_NList_Active, mi->Pos);
  1577.    return mi->Pos;
  1578. }
  1579. ///
  1580. /// DisplayMailList
  1581. //  Lists folder contents in the message listview
  1582. void DisplayMailList(struct Folder *fo, APTR lv)
  1583. {
  1584.    struct Mail *work, **array;
  1585.  
  1586.    if ((array = (struct Mail **)calloc(fo->Total+1,sizeof(struct Mail *))))
  1587.    {
  1588.       int i = 0;
  1589.       Busy(GetStr(MSG_BusyDisplayingList), "", 0, 0);
  1590.       for (work = fo->Messages; work; work = work->Next) array[i++] = work;
  1591.       set(lv, MUIA_NList_Quiet, TRUE);
  1592.       DoMethod(lv, MUIM_NList_Clear);
  1593.       DoMethod(lv, MUIM_NList_Insert, array, fo->Total, MUIV_NList_Insert_Sorted);
  1594.       set(lv, MUIA_NList_Quiet, FALSE);
  1595.       free(array);
  1596.       BusyEnd;
  1597.    }
  1598. }
  1599. ///
  1600. /// AddMailToList
  1601. //  Adds a message to a folder
  1602. struct Mail *AddMailToList(struct Mail *mail, struct Folder *folder)
  1603. {
  1604.    struct Mail *new = malloc(sizeof(struct Mail));
  1605.    if (new)
  1606.    {
  1607.       *new = *mail;
  1608.       new->Folder = folder;
  1609.       MyAddTail(&(folder->Messages), new);
  1610.       folder->Total++;
  1611.       folder->Size += mail->Size;
  1612.       if (mail->Status == STATUS_NEW) { folder->New++; folder->Unread++; }
  1613.       if (mail->Status == STATUS_UNR) folder->Unread++;
  1614.       MA_ExpireIndex(folder);
  1615.    }
  1616.    return new;
  1617. }
  1618. ///
  1619. /// RemoveMailFromList
  1620. //  Removes a message from a folder
  1621. void RemoveMailFromList(struct Mail *mail)
  1622. {
  1623.    struct Folder *folder = mail->Folder;
  1624.    folder->Total--;
  1625.    folder->Size -= mail->Size;
  1626.    if (mail->Status == STATUS_NEW) { folder->New--; folder->Unread--; }
  1627.    if (mail->Status == STATUS_UNR) folder->Unread--;
  1628.    MA_ExpireIndex(folder);
  1629.    MyRemove(&(folder->Messages), mail);
  1630.    free(mail);
  1631. }
  1632. ///
  1633. /// ClearMailList
  1634. //  Removes all messages from a folder
  1635. void ClearMailList(struct Folder *folder, BOOL resetstats)
  1636. {
  1637.    struct Mail *work, *next;
  1638.    for (work = folder->Messages; work; work = next)
  1639.    {
  1640.       next = work->Next;
  1641.       free(work);
  1642.    }
  1643.    if (resetstats) folder->Total = folder->New = folder->Unread = folder->Size = 0;
  1644.    folder->Messages = NULL;
  1645. }
  1646. ///
  1647. /// GetPackMethod
  1648. //  Returns packer type and efficiency
  1649. LOCAL BOOL GetPackMethod(int xpktype, char **method, int *eff)
  1650. {
  1651.    if (xpktype == 2) { *method = C->XPKPack; *eff = C->XPKPackEff; return TRUE; }
  1652.    if (xpktype == 3) { *method = C->XPKPackEncrypt; *eff = C->XPKPackEncryptEff; return TRUE; }
  1653.    return FALSE;
  1654. }
  1655. ///
  1656. /// CompressMailFile
  1657. //  Shrinks a message file
  1658. LOCAL BOOL CompressMailFile(char *src, char *dst, char *passwd, char *method, int eff)
  1659. {
  1660.    int err;
  1661.    if (!XpkBase) return FALSE;
  1662.    err = XpkPackTags(XPK_InName, src, XPK_OutName, dst, XPK_Password, passwd, XPK_PackMethod, method, XPK_PackMode, eff, TAG_DONE);
  1663.    return (BOOL)!err;
  1664. }
  1665. ///
  1666. /// UncompressMailFile
  1667. //  Expands a compressed message file
  1668. LOCAL BOOL UncompressMailFile(char *src, char *dst, char *passwd)
  1669. {
  1670.    if (!XpkBase) return FALSE;
  1671.    return (BOOL)(!XpkUnpackTags(XPK_InName, src, XPK_OutName, dst, XPK_Password, passwd, TAG_DONE));
  1672. }
  1673. ///
  1674. /// TransferMailFile
  1675. //  Copies or moves a message file, handles compression
  1676. BOOL TransferMailFile(BOOL copyit, struct Mail *mail, struct Folder *dstfolder)
  1677. {
  1678.    char *pmeth, srcbuf[SIZE_PATHFILE], dstbuf[SIZE_PATHFILE];
  1679.    struct Folder *srcfolder = mail->Folder;
  1680.    int peff = 0;
  1681.    int srcxpk = srcfolder->XPKType, dstxpk = dstfolder->XPKType;
  1682.    char *srcpw = srcfolder->Password, *dstpw = dstfolder->Password;
  1683.    BOOL one2one, needuncomp, needcomp, done = FALSE, success = FALSE;
  1684.  
  1685.    if (!MA_GetIndex(srcfolder)) return FALSE;
  1686.    if (!MA_GetIndex(dstfolder)) return FALSE;
  1687.    one2one = (srcxpk == dstxpk) && (srcxpk != 3);
  1688.    needuncomp = srcxpk > 1;
  1689.    needcomp   = dstxpk > 1;
  1690.    GetPackMethod(dstxpk, &pmeth, &peff);
  1691.    GetMailFile(srcbuf, srcfolder, mail);
  1692.    strcpy(dstbuf, MA_NewMailFile(dstfolder, mail->MailFile, atoi(mail->MailFile)));
  1693.    if (one2one && !copyit) if ((done = RenameFile(srcbuf, dstbuf))) success = TRUE;
  1694.    if (!done)
  1695.    {
  1696.       if (needuncomp)
  1697.          if (needcomp)
  1698.             if (one2one)
  1699.                success = CopyFile(dstbuf, 0, srcbuf, 0);
  1700.             else
  1701.             {
  1702.                struct TempFile *tf = OpenTempFile(NULL);
  1703.                if (UncompressMailFile(srcbuf, tf->Filename, srcpw))
  1704.                   success = CompressMailFile(tf->Filename, dstbuf, dstpw, pmeth, peff);
  1705.                CloseTempFile(tf);
  1706.             }
  1707.          else
  1708.             success = UncompressMailFile(srcbuf, dstbuf, srcpw);
  1709.       else
  1710.          if (needcomp)
  1711.             success = CompressMailFile(srcbuf, dstbuf, dstpw, pmeth, peff);
  1712.          else
  1713.             success = CopyFile(dstbuf, 0, srcbuf, 0);
  1714.       if (success && !copyit) DeleteFile(srcbuf);
  1715.       if (success) SetComment(dstbuf, Status[mail->Status]);
  1716.    }
  1717.    return success;
  1718. }
  1719. ///
  1720. /// RepackMailFile
  1721. //  (Re/Un)Compresses a message file
  1722. BOOL RepackMailFile(struct Mail *mail, int dstxpk, char *passwd)
  1723. {
  1724.    char *pmeth = NULL, srcbuf[SIZE_PATHFILE], dstbuf[SIZE_PATHFILE];
  1725.    struct Folder *folder = mail->Folder;
  1726.    int peff = 0, srcxpk = folder->XPKType;
  1727.    BOOL success = TRUE;
  1728.  
  1729.    MA_GetIndex(folder);
  1730.    GetMailFile(srcbuf, folder, mail);
  1731.    GetPackMethod(dstxpk, &pmeth, &peff);
  1732.    sprintf(dstbuf, "%s.tmp", srcbuf);
  1733.    switch (4*srcxpk+dstxpk)
  1734.    {
  1735.       case  0: case  5: case 10: case 15:
  1736.       case  1: case  4:                   return TRUE;
  1737.       case  2: case  3: case  6: case  7: if ((success = CompressMailFile(srcbuf, dstbuf, passwd, pmeth, peff)))
  1738.                                           {
  1739.                                              DeleteFile(srcbuf);
  1740.                                              success = RenameFile(dstbuf, srcbuf);
  1741.                                           }
  1742.                                           break;
  1743.       case  8: case 9:  case 12: case 13: if ((success = UncompressMailFile(srcbuf, dstbuf, folder->Password)))
  1744.                                           {
  1745.                                              DeleteFile(srcbuf);
  1746.                                              success = RenameFile(dstbuf, srcbuf);
  1747.                                           }
  1748.                                           break;
  1749.       case 11: case 14:                   if ((success = UncompressMailFile(srcbuf, dstbuf, folder->Password)))
  1750.                                           {
  1751.                                              success = CompressMailFile(dstbuf, srcbuf, passwd, pmeth, peff);
  1752.                                              DeleteFile(dstbuf);
  1753.                                           }
  1754.                                           break;
  1755.    }
  1756.    MA_SetMailStatus(mail, mail->Status);
  1757.    return success;
  1758. }
  1759. ///
  1760. /// DoPack
  1761. //  Compresses a file
  1762. BOOL DoPack(char *file, char *newfile, struct Folder *folder)
  1763. {
  1764.    char *pmeth = NULL;
  1765.    int peff = 0;
  1766.  
  1767.    GetPackMethod(folder->XPKType, &pmeth, &peff);
  1768.    if (!CompressMailFile(file, newfile, folder->Password, pmeth, peff)) return FALSE;
  1769.    DeleteFile(file);
  1770.    return TRUE;
  1771. }
  1772. ///
  1773. /// StartUnpack
  1774. //  Unpacks a file to a temporary file
  1775. char *StartUnpack(char *file, char *newfile, struct Folder *folder)
  1776. {
  1777.    FILE *fh;
  1778.    BOOL xpk = FALSE;
  1779.    if ((fh = fopen(file, "r")))
  1780.    {
  1781.       if (fgetc(fh) == 'X') if (fgetc(fh) == 'P') if (fgetc(fh) == 'K') xpk = TRUE;
  1782.       fclose(fh);
  1783.       if (xpk)
  1784.       {
  1785.          char nfile[SIZE_FILE];
  1786.          stcgfn(nfile, file); sprintf(&nfile[strlen(nfile)], "_%08lx.unp", folder);
  1787.          strmfp(newfile, C->TempDir, nfile);
  1788.          if (FileSize(newfile) < 0) if (!UncompressMailFile(file, newfile, folder ? folder->Password : "")) return NULL;
  1789.       }
  1790.       else strcpy(newfile, file);
  1791.       return newfile;
  1792.    }
  1793.    return NULL;
  1794. }
  1795. ///
  1796. /// FinishUnpack
  1797. //  Deletes temporary unpacked file
  1798. void FinishUnpack(char *file)
  1799. {
  1800.    if (strstr(file, ".unp")) DeleteFile(file);
  1801. }
  1802. ///
  1803. /// IsValidMailFile
  1804. //  Checks if a message file name is valid
  1805. BOOL IsValidMailFile(char *fname)
  1806. {
  1807.    int l = strlen(fname);
  1808.    if (l < 7 || l > 10 || fname[5] != '.') return FALSE;
  1809.    while (--l >= 0) if (l != 5 && !isdigit(fname[l])) return FALSE;
  1810.    return TRUE;
  1811. }
  1812. ///
  1813.  
  1814. /*** Editor related ***/
  1815. /// EditorToFile
  1816. //  Saves contents of a texteditor object to a file
  1817. BOOL EditorToFile(struct Object *editor, char *file, struct TranslationTable *tt)
  1818. {
  1819.    char *text;
  1820.    UBYTE *p;
  1821.    FILE *fh;
  1822.  
  1823.    if (!(fh = fopen(file, "w"))) return FALSE;
  1824.    text = (char *)DoMethod((Object *)editor, MUIM_TextEditor_ExportText);
  1825.    if (tt) for (p = text; *p; ++p) *p = tt->Table[*p];
  1826.    fputs(text, fh);
  1827.    fclose(fh);
  1828.    FreeVec(text);
  1829.    return TRUE;
  1830. }
  1831. ///
  1832. /// FileToEditor
  1833. //  Loads a file into a texteditor object
  1834. BOOL FileToEditor(char *file, struct Object *editor)
  1835. {
  1836.    char *text = FileToBuffer(file);
  1837.    if (!text) return FALSE;
  1838.    set(editor, MUIA_TextEditor_Contents, text);
  1839.    free(text);
  1840.    return TRUE;
  1841. }
  1842. ///
  1843.  
  1844. /*** Hooks ***/
  1845. /// GeneralDesFunc
  1846. //  General purpose destruction hook
  1847. long SAVEDS ASM GeneralDesFunc(REG(a1,void *entry))
  1848. {
  1849.    free(entry);
  1850.    return 0;
  1851. }
  1852. MakeHook(GeneralDesHook, GeneralDesFunc);
  1853. ///
  1854. /// PO_SetPublicKey
  1855. //  Copies public PGP key from list to string gadget
  1856. void SAVEDS ASM PO_SetPublicKey(REG(a1,APTR string), REG(a2,APTR pop))
  1857. {
  1858.    char *var, buf[SIZE_SMALL];
  1859.  
  1860.    DoMethod(pop, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &var);
  1861.    if (var)
  1862.    {
  1863.       strcpy(buf, "0x");
  1864.       strncat(buf, var, 8);
  1865.       setstring(string, buf);
  1866.    }
  1867. }
  1868. MakeHook(PO_SetPublicKeyHook, PO_SetPublicKey);
  1869. ///
  1870. /// PO_ListPublicKeys
  1871. //  Lists keys of public PGP keyring in a popup window
  1872. long SAVEDS ASM PO_ListPublicKeys(REG(a1,APTR string), REG(a2,APTR pop))
  1873. {  
  1874.    BOOL secret;
  1875.    char buf[SIZE_LARGE], *str, p;
  1876.    int retc, keys = 0;
  1877.    FILE *fp;
  1878.  
  1879.    get(pop, MUIA_UserData, &str); secret = (BOOL)(str != NULL);  // MUIA_UserData is actually BOOL already, but 32bit!
  1880.    if (G->PGPVersion == 5)
  1881.       retc = PGPCommand("pgpk", "-l +language=us", KEEPLOG);
  1882.    else
  1883.    {
  1884.       strcpy(buf, "-kv  ");
  1885.       if (secret)
  1886.       {
  1887.          GetVar("PGPPATH", &buf[4], SIZE_DEFAULT, 0);
  1888.          if ((p = buf[strlen(buf)-1]) != ':' && p != '/') strcat(buf, "/");
  1889.          strcat(buf, "secring.pgp");
  1890.       }
  1891.       retc = PGPCommand("pgp", buf, KEEPLOG);
  1892.    }
  1893.    if (!retc) if ((fp = fopen(PGPLOGFILE, "r")))
  1894.    {
  1895.       get(string, MUIA_String_Contents, &str);
  1896.       DoMethod(pop, MUIM_List_Clear);
  1897.       while (GetLine(fp, buf, sizeof(buf)))
  1898.       {
  1899.          char entry[SIZE_DEFAULT];
  1900.          clear(entry, SIZE_DEFAULT);
  1901.          if (G->PGPVersion == 5)
  1902.          {
  1903.             if (!strncmp(buf, "sec", 3) || (!strncmp(&buf[1], "ub", 2) && !secret))
  1904.             {
  1905.                memcpy(entry, &buf[12], 8);
  1906.                while (GetLine(fp, buf, sizeof(buf)))
  1907.                   if (!strncmp(buf, "uid", 3)) { strncat(entry, &buf[4], SIZE_DEFAULT-9); break; }
  1908.             }
  1909.          }
  1910.          else
  1911.          {
  1912.             if (buf[9] == '/' && buf[23] == '/')
  1913.             {
  1914.                memcpy(entry, &buf[10], 8);
  1915.                strncat(entry, &buf[29], SIZE_DEFAULT-8);
  1916.             }
  1917.          }
  1918.          if (*entry)
  1919.          {
  1920.             DoMethod(pop, MUIM_List_InsertSingle, entry, MUIV_List_Insert_Bottom);
  1921.             if (!strncmp(entry, str, 8)) set(pop, MUIA_List_Active, keys);
  1922.             keys++;
  1923.          }
  1924.       }
  1925.       fclose(fp);
  1926.       DeleteFile(PGPLOGFILE);
  1927.    }
  1928.    if (!keys) ER_NewError(GetStr(MSG_ER_NoPublicKeys), "", "");
  1929.    return keys > 0;
  1930. }
  1931. MakeHook(PO_ListPublicKeysHook, PO_ListPublicKeys);
  1932. ///
  1933.  
  1934. /*** MUI related ***/
  1935. /// ShortCut
  1936. //  Finds keyboard shortcut in text label
  1937. char ShortCut(char *label)
  1938. {
  1939.    char *ptr = strchr(label, '_');
  1940.  
  1941.    if (!ptr) return 0;
  1942.    return (char)ToLower(*++ptr);
  1943. }
  1944.  
  1945. /*********** Function isn't used anywhere! -msbethke **************
  1946. ///
  1947. /// RemoveCut
  1948. //  Removes shortcut character from text label
  1949. LOCAL char *RemoveCut(char *label)
  1950. {
  1951.    static char lab[SIZE_DEFAULT], *p;
  1952.  
  1953.    for (p = lab; *label; label++) if (*label != '_') *p++ = *label;
  1954.    *p = 0;
  1955.    return lab;
  1956. }
  1957. */
  1958.  
  1959. ///
  1960. /// SetHelp
  1961. //  Sets bubble help of a MUI object
  1962. void SetHelp(APTR object, APTR strnum)
  1963. {
  1964.    set(object, MUIA_ShortHelp, GetStr(strnum));
  1965. }
  1966. ///
  1967. /// MakeCycle
  1968. //  Creates a MUI cycle object
  1969. Object *MakeCycle(char **labels, char *label)
  1970. {
  1971.    Object *obj = KeyCycle(labels, ShortCut(label));
  1972.    if (obj) set(obj, MUIA_CycleChain, 1);
  1973.    return obj;
  1974. }
  1975. ///
  1976. /// MakeButton
  1977. //  Creates a MUI button
  1978. Object *MakeButton(char *txt)
  1979. {
  1980.    Object *obj = MUI_MakeObject(MUIO_Button,txt);
  1981.    if (obj) set(obj, MUIA_CycleChain, 1);
  1982.    return obj;
  1983. }
  1984. ///
  1985. /// MakeCheck
  1986. //  Creates a MUI checkmark object
  1987. Object *MakeCheck(char *label)
  1988. {
  1989.    return 
  1990.    ImageObject,
  1991.       ImageButtonFrame,
  1992.       MUIA_InputMode   , MUIV_InputMode_Toggle,
  1993.       MUIA_Image_Spec  , MUII_CheckMark, 
  1994.       MUIA_Background  , MUII_ButtonBack, 
  1995.       MUIA_ShowSelState, FALSE,
  1996.       MUIA_ControlChar , ShortCut(label),
  1997.       MUIA_CycleChain  , 1,
  1998.    End;
  1999. }
  2000. ///
  2001. /// MakeCheckGroup
  2002. //  Creates a labelled MUI checkmark object
  2003. Object *MakeCheckGroup(Object **check, char *label)
  2004. {
  2005.    return 
  2006.    HGroup,
  2007.       Child, *check = MakeCheck(label),
  2008.       Child, Label1(label),
  2009.       Child, HSpace(0),
  2010.    End;
  2011. }
  2012. ///
  2013. /// MakeString
  2014. //  Creates a MUI string object
  2015. Object *MakeString(int maxlen, char *label)
  2016. {
  2017.    return BetterStringObject,
  2018.       StringFrame,
  2019.       MUIA_String_MaxLen     , maxlen,
  2020.       MUIA_String_AdvanceOnCR, TRUE,
  2021.       MUIA_ControlChar       , ShortCut(label),
  2022.       MUIA_CycleChain        , 1,
  2023.    End;
  2024. }
  2025. ///
  2026. /// MakePassString
  2027. //  Creates a MUI string object with hidden text
  2028. Object *MakePassString(char *label)
  2029. {
  2030.    return BetterStringObject,
  2031.       StringFrame,
  2032.       MUIA_String_MaxLen     , SIZE_PASSWORD,
  2033.       MUIA_String_Secret     , TRUE,
  2034.       MUIA_String_AdvanceOnCR, TRUE,
  2035.       MUIA_ControlChar       , ShortCut(label),
  2036.       MUIA_CycleChain        , 1,
  2037.    End;
  2038. }
  2039. ///
  2040. /// MakeInteger
  2041. //  Creates a MUI string object for numeric input
  2042. Object *MakeInteger(int maxlen, char *label)
  2043. {
  2044.    Object *str = MakeString(maxlen, label);
  2045.    if (str)
  2046.    {
  2047.       set(str, MUIA_String_Integer, 0);
  2048.       set(str, MUIA_String_Accept, "0123456789");
  2049.    }
  2050.    return str;
  2051. }
  2052. ///
  2053. /// MakePGPKeyList
  2054. //  Creates a PGP id popup list
  2055. Object *MakePGPKeyList(APTR *st, BOOL secret, char *label)
  2056. {
  2057.    APTR po, lv;
  2058.  
  2059.    if ((po = PopobjectObject,
  2060.          MUIA_Popstring_String, *st = MakeString(SIZE_DEFAULT, label),
  2061.          MUIA_Popstring_Button, PopButton(MUII_PopUp),
  2062.          MUIA_Popobject_StrObjHook, &PO_ListPublicKeysHook,
  2063.          MUIA_Popobject_ObjStrHook, &PO_SetPublicKeyHook,
  2064.          MUIA_Popobject_WindowHook, &PO_WindowHook,
  2065.          MUIA_Popobject_Object, lv = ListviewObject,
  2066.             MUIA_UserData, secret,
  2067.             MUIA_Listview_List, ListObject,
  2068.                InputListFrame,
  2069.                MUIA_List_AdjustWidth, TRUE,
  2070.                MUIA_List_ConstructHook, MUIV_List_ConstructHook_String,
  2071.                MUIA_List_DestructHook, MUIV_List_DestructHook_String,
  2072.             End,
  2073.          End,
  2074.       End))
  2075.       DoMethod(lv, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE, po, 2, MUIM_Popstring_Close, TRUE);
  2076.    return po;
  2077. }
  2078. ///
  2079. /// MakePicture
  2080. //  Creates a MUI image object that uses image datatypes
  2081. Object *MakePicture(char *fname)
  2082. {
  2083.    return G->DtpicSupported ?
  2084.       MUI_NewObject("Dtpic.mui", MUIA_Dtpic_Name, fname, End :
  2085.       NewObject(CL_BodyChunk->mcc_Class,NULL, MUIA_Bodychunk_File, fname, End;
  2086. }
  2087. ///
  2088. /// MakeStatusFlag
  2089. //  Creates a MUI object for status images
  2090. Object *MakeStatusFlag(char *fname)
  2091. {
  2092.    return NewObject(CL_BodyChunk->mcc_Class,NULL,
  2093.       MUIA_Bodychunk_File, fname,
  2094.       MUIA_Bodychunk_UseOld, TRUE,
  2095.       MUIA_Bitmap_Transparent, 0,
  2096.    End;
  2097. }
  2098. ///
  2099. /// MakeNumeric
  2100. //  Creates a MUI numeric slider
  2101. Object *MakeNumeric(int min, int max, BOOL percent)
  2102. {
  2103.    return
  2104.    NumericbuttonObject,
  2105.       MUIA_Numeric_Min, min,
  2106.       MUIA_Numeric_Max, max,
  2107.       MUIA_Numeric_Format, percent ? "%ld%%" : "%ld",
  2108.       MUIA_CycleChain, 1,
  2109.    End;
  2110. }
  2111. ///
  2112. /// MakeMenuitem
  2113. //  Creates a menu item from a catalog string
  2114. Object *MakeMenuitem(const UBYTE *str, ULONG ud)
  2115. {
  2116.    if (str == NULL) return (MenuitemObject, MUIA_Menuitem_Title, NM_BARLABEL, End);
  2117.  
  2118.    if (str[1] == '\0')
  2119.       return (MenuitemObject,
  2120.          MUIA_Menuitem_Title, str+2,
  2121.          MUIA_Menuitem_Shortcut, str,
  2122.          MUIA_UserData, ud,
  2123.          End);
  2124.    else
  2125.       return (MenuitemObject,
  2126.          MUIA_Menuitem_Title, str,
  2127.          MUIA_UserData, ud,
  2128.          End);
  2129. }
  2130. ///
  2131. /// SetupToolbar
  2132. //  Initializes a single button in a MUI toolbar object
  2133. void SetupToolbar(struct MUIP_Toolbar_Description *tb, char *label, char *help, UWORD flags)
  2134. {
  2135.    tb->Type = label ? (*label ? TDT_BUTTON : TDT_SPACE) : TDT_END;
  2136.    tb->Flags = flags;
  2137.    tb->ToolText = tb->Type == TDT_BUTTON ? label : NULL;
  2138.    tb->HelpString = help;
  2139.    tb->MutualExclude = 0; tb->Key = 0;
  2140. }
  2141. ///
  2142. /// SetupMenu
  2143. //  Initializes a MUI menu item
  2144. void SetupMenu(int type, struct NewMenu *menu, char *label, char *shortcut, int id)
  2145. {
  2146.    menu->nm_Type = type;
  2147.    menu->nm_Label = (STRPTR)label;
  2148.    menu->nm_CommKey = (STRPTR)shortcut;
  2149.    menu->nm_Flags = 0;
  2150.    menu->nm_MutualExclude = 0;
  2151.    menu->nm_UserData = (APTR)id;
  2152. }
  2153. ///
  2154. /// DoSuperNew
  2155. //  Calls parent NEW method within a subclass
  2156. #ifdef __MORPHOS__
  2157. ULONG DoSuperNew(struct IClass *cl, Object *obj, ULONG tag1, ...)
  2158. {
  2159.    ULONG tags[4 * 2];
  2160.    va_list args;
  2161.    // SVR4 varargs to Tags hack.
  2162.    va_start(args, tag1);
  2163.    tags[0] = tag1;
  2164.    memcpy(tags + 1, args->reg_save_area + 3 * 4, 5 * 4);
  2165.    tags[6] = TAG_MORE;
  2166.    tags[7] = (ULONG)args->overflow_arg_area;
  2167.    va_end(args);
  2168.    return DoSuperMethod(cl, obj, OM_NEW, tags, NULL);
  2169. }
  2170. #else
  2171. ULONG DoSuperNew(struct IClass *cl, Object *obj, ULONG tag1, ...)
  2172. {
  2173.    return DoSuperMethod(cl, obj, OM_NEW, &tag1, NULL);
  2174. }
  2175. #endif
  2176. ///
  2177. /// GetMUI
  2178. //  Gets an attribute value from a MUI object
  2179. int GetMUI(struct Object *obj,int attr)
  2180. {
  2181.    LONG b;
  2182.    get(obj,attr,&b);
  2183.    return (int)b;
  2184. }
  2185. ///
  2186. /// GetMUIStringPtr
  2187. //  Returns a pointer to the value of a MUI string object
  2188. char *GetMUIStringPtr(struct Object *obj)
  2189. {
  2190.     return (char*)GetMUI(obj,MUIA_String_Contents);
  2191. }
  2192. ///
  2193. /// GetMUIString
  2194. //  Returns the value of a MUI string object
  2195. void GetMUIString(char *a,struct Object *obj)
  2196. {
  2197.    strcpy(a,(char*)GetMUI(obj,MUIA_String_Contents));
  2198. }
  2199. ///
  2200. /// GetMUIText
  2201. //  Returns the value of a MUI text object
  2202. void GetMUIText(char *a,struct Object *obj)
  2203. {
  2204.    strcpy(a,(char*)GetMUI(obj,MUIA_Text_Contents));
  2205. }
  2206. ///
  2207. /// GetMUIInteger
  2208. //  Returns the numeric value of a MUI string object
  2209. int GetMUIInteger(struct Object *obj)
  2210. {
  2211.    return GetMUI(obj,MUIA_String_Integer);
  2212. }
  2213. ///
  2214. /// GetMUICheck
  2215. //  Returns the value of a MUI checkmark object
  2216. BOOL GetMUICheck(struct Object *obj)
  2217. {
  2218.    return (BOOL)GetMUI(obj, MUIA_Selected);
  2219. }
  2220. ///
  2221. /// GetMUICycle
  2222. //  Returns the value of a MUI cycle object
  2223. int GetMUICycle(struct Object *obj)
  2224. {
  2225.    return GetMUI(obj, MUIA_Cycle_Active);
  2226. }
  2227. ///
  2228. /// GetMUIRadio
  2229. //  Returns the value of a MUI radio object
  2230. int GetMUIRadio(struct Object *obj)
  2231. {
  2232.    return GetMUI(obj, MUIA_Radio_Active);
  2233. }
  2234. ///
  2235. /// GetMUINumer
  2236. //  Returns the value of a MUI numeric slider
  2237. int GetMUINumer(struct Object *obj)
  2238. {
  2239.    return GetMUI(obj, MUIA_Numeric_Value);
  2240. }
  2241. ///
  2242. /// SafeOpenWindow
  2243. //  Tries to open a window
  2244. BOOL SafeOpenWindow(struct Object *obj)
  2245. {
  2246.    int isopen, isicon;
  2247.    set(obj, MUIA_Window_Open, TRUE);
  2248.    get(obj, MUIA_Window_Open, &isopen);
  2249.    get(_app(obj), MUIA_Application_Iconified, &isicon);
  2250.    if (isopen || isicon) return TRUE;
  2251.    DisplayBeep(0);
  2252.    return FALSE;
  2253. }
  2254. ///
  2255. /// DisposeModule
  2256. //  Frees resources of a MUI window
  2257. void DisposeModulePush(void *module)
  2258. {
  2259.    DoMethod(G->App, MUIM_Application_PushMethod, G->App, 3, MUIM_CallHook, &DisposeModuleHook, module);
  2260. }
  2261. void DisposeModule(void *modptr)
  2262. {
  2263.    struct UniversalClassData **module = (struct UniversalClassData **)modptr;
  2264.    if (*module)
  2265.    {
  2266.       APTR window = (*module)->GUI.WI;
  2267.       set(window, MUIA_Window_Open, FALSE);
  2268.       DoMethod(G->App, OM_REMMEMBER, window);
  2269. #ifndef __SASC
  2270.       if(modptr!=&G->WR[0] && modptr!=&G->WR[1] && modptr!=&G->WR[2])
  2271. #endif
  2272.       MUI_DisposeObject(window);
  2273.       free(*module);
  2274.       *module = NULL;
  2275.    }
  2276. }
  2277. void SAVEDS ASM DisposeModuleFunc(REG(a1,void **arg))
  2278. {
  2279.    DisposeModule(arg[0]);
  2280. }
  2281. MakeHook(DisposeModuleHook,DisposeModuleFunc);
  2282. ///
  2283. /// LoadLayout
  2284. //  Loads column widths from ENV:MUI/YAM.cfg
  2285. void LoadLayout(void)
  2286. {
  2287.    char *ls;
  2288.    DoMethod(G->App, MUIM_Application_Load, MUIV_Application_Load_ENV);
  2289.    if (!*(ls = GetMUIStringPtr(G->MA->GUI.ST_LAYOUT))) ls = "35 100 25 100 30 100";
  2290.    sscanf(ls, "%ld %ld %ld %ld %ld %ld", &G->Weights[0], &G->Weights[1], &G->Weights[2], &G->Weights[3], &G->Weights[4], &G->Weights[5]);
  2291. }
  2292. ///
  2293. /// SaveLayout
  2294. //  Saves column widths to ENV(ARC):MUI/YAM.cfg
  2295. void SaveLayout(BOOL permanent)
  2296. {
  2297.    char buf[SIZE_DEFAULT];
  2298.    sprintf(buf, "%ld %ld %ld %ld %ld %ld", G->Weights[0], G->Weights[1], G->Weights[2], G->Weights[3], G->Weights[4], G->Weights[5]);
  2299.    setstring(G->MA->GUI.ST_LAYOUT, buf);
  2300.    DoMethod(G->App, MUIM_Application_Save, MUIV_Application_Save_ENV);
  2301.    if (permanent) DoMethod(G->App, MUIM_Application_Save, MUIV_Application_Save_ENVARC);
  2302. }
  2303. ///
  2304. /// ConvertKey
  2305. //  Converts input event to key code
  2306. ULONG ConvertKey(struct IntuiMessage *imsg)
  2307. {
  2308.    struct InputEvent event;
  2309.    UBYTE code = 0;
  2310.    event.ie_NextEvent    = NULL;
  2311.    event.ie_Class        = IECLASS_RAWKEY;
  2312.    event.ie_SubClass     = 0;
  2313.    event.ie_Code         = imsg->Code;
  2314.    event.ie_Qualifier    = imsg->Qualifier;
  2315.    event.ie_EventAddress = (APTR *) *((ULONG *)imsg->IAddress);
  2316.    MapRawKey(&event, &code, 1, NULL);
  2317.    return code;
  2318. }
  2319. ///
  2320.  
  2321. /**** BodyChunk ****/
  2322. /// FreeBCImage
  2323. //  Frees a bodychunk image
  2324. void FreeBCImage(struct BodyChunkData *bcd)
  2325. {
  2326.    if (bcd)
  2327.    {
  2328.       if (bcd->Colors) free(bcd->Colors);
  2329.       if (bcd->Body) free(bcd->Body);
  2330.       free(bcd);
  2331.    }
  2332. }
  2333. ///
  2334. /// GetBCImage
  2335. //  Searches for a bodychunk image by filename
  2336. struct BodyChunkData *GetBCImage(char *fname)
  2337. {
  2338.    int i;
  2339.    for (i = 0; i < MAXIMAGES; i++)
  2340.       if (G->BImage[i]) if (!strcmp(G->BImage[i]->File, fname)) return G->BImage[i];
  2341.    return NULL;
  2342. }
  2343. ///
  2344. /// LoadBCImage
  2345. //  Loads a bodychunk image from disk
  2346. struct BodyChunkData *LoadBCImage(char *fname)
  2347. {
  2348.    struct IFFHandle *iff;
  2349.    struct ContextNode *cn;
  2350.    struct BodyChunkData *bcd;
  2351.  
  2352.    if ((bcd = calloc(1,sizeof(struct BodyChunkData))))
  2353.    {
  2354.       if ((iff = AllocIFF()))
  2355.       {
  2356.          if ((iff->iff_Stream = Open(fname, MODE_OLDFILE)))
  2357.          {
  2358.             InitIFFasDOS(iff);
  2359.             if (!OpenIFF(iff, IFFF_READ))
  2360.             {
  2361.                if (!ParseIFF(iff, IFFPARSE_STEP))
  2362.                {
  2363.                   if ((cn=CurrentChunk(iff)) && (cn->cn_ID == ID_FORM))
  2364.                   {
  2365.                      if (cn->cn_Type == ID_ILBM)
  2366.                      {
  2367.                         struct StoredProperty *sp;
  2368.                         struct BitMapHeader *bmhd;
  2369.                         int i, size;
  2370.  
  2371.                         if (!PropChunk (iff, ID_ILBM, ID_BMHD) &&
  2372.                             !PropChunk (iff, ID_ILBM, ID_CMAP) &&
  2373.                             !StopChunk (iff, ID_ILBM, ID_BODY) &&
  2374.                             !StopOnExit(iff, ID_ILBM, ID_FORM) &&
  2375.                             !ParseIFF  (iff, IFFPARSE_SCAN))
  2376.                         {
  2377.                            if ((sp = FindProp(iff, ID_ILBM, ID_CMAP)))
  2378.                            {
  2379.                               bcd->Colors = calloc(sp->sp_Size,sizeof(ULONG));
  2380.                               for (i = 0; i < sp->sp_Size; i++)
  2381.                               {
  2382.                                  UBYTE c = ((UBYTE *)sp->sp_Data)[i];
  2383.                                  bcd->Colors[i] = (c<<24)|(c<<16)|(c<<8)|c;
  2384.                               }
  2385.                            }
  2386.                            if ((sp = FindProp(iff,ID_ILBM,ID_BMHD)))
  2387.                            {
  2388.                               bmhd = (struct BitMapHeader *)sp->sp_Data;
  2389.                               if (bmhd->bmh_Compression == cmpNone || bmhd->bmh_Compression==cmpByteRun1)
  2390.                               {
  2391.                                  size = CurrentChunk(iff)->cn_Size;
  2392.                                  if ((bcd->Body = calloc(size,1)))
  2393.                                  {
  2394.                                     if (ReadChunkBytes(iff, bcd->Body, size) == size)
  2395.                                     {
  2396.                                        bcd->Width  = bmhd->bmh_Width;
  2397.                                        bcd->Height = bmhd->bmh_Height;
  2398.                                        bcd->Depth = bmhd->bmh_Depth;
  2399.                                        bcd->Compression = bmhd->bmh_Compression;
  2400.                                        bcd->Masking = bmhd->bmh_Masking;
  2401.                                        stcgfn(bcd->File, fname);
  2402.                                     }
  2403.                                  }
  2404.                               }
  2405.                            }
  2406.                         }
  2407.                      }
  2408.                   }
  2409.                }
  2410.             }
  2411.             CloseIFF(iff);
  2412.          }
  2413.          Close(iff->iff_Stream);
  2414.       }
  2415.       FreeIFF(iff);
  2416.    }
  2417.    else return NULL;
  2418.    if (!bcd->Depth) { FreeBCImage(bcd); return NULL; }
  2419.    return bcd;
  2420. }
  2421. ///
  2422.  
  2423. /*** Miscellaneous stuff ***/
  2424. /// PGPGetPassPhrase
  2425. //  Asks user for the PGP passphrase
  2426. void PGPGetPassPhrase(void)
  2427. {
  2428.    if (!G->PGPPassPhrase[0])
  2429.    {
  2430.       G->PGPPassVolatile = FALSE;
  2431.       if (GetVar("PGPPASS", G->PGPPassPhrase, SIZE_DEFAULT, 0) < 0)
  2432.       {
  2433.          char pgppass[SIZE_DEFAULT];
  2434.          G->PGPPassVolatile = TRUE; *pgppass = 0;
  2435.          if (StringRequest(pgppass, SIZE_DEFAULT, "PGP", GetStr(MSG_UT_PGPPassReq), GetStr(MSG_Okay), NULL, GetStr(MSG_Cancel), TRUE, G->MA->GUI.WI))
  2436.             strcpy(G->PGPPassPhrase, pgppass);
  2437.       }
  2438.       else return;
  2439.    }
  2440.    SetVar("PGPPASS", G->PGPPassPhrase, -1, GVF_GLOBAL_ONLY);
  2441. }
  2442. ///
  2443. /// PGPClearPassPhrase
  2444. //  Clears the ENV variable containing the PGP passphrase
  2445. void PGPClearPassPhrase(BOOL force)
  2446. {
  2447.    if (G->PGPPassVolatile) DeleteVar("PGPPASS", 0);
  2448.    if (force) G->PGPPassPhrase[0] = 0;
  2449. }
  2450. ///
  2451. /// PGPCommand
  2452. //  Launches a PGP command
  2453. int PGPCommand(char *progname, char *options, int flags)
  2454. {
  2455.    BPTR fhi,fho;
  2456.    int error = -1;
  2457.    char command[SIZE_LARGE];
  2458.  
  2459.     if ((fhi = Open("NIL:", MODE_OLDFILE)))
  2460.     {
  2461.        if ((fho = Open("NIL:", MODE_NEWFILE)))
  2462.        {
  2463.           Busy(GetStr(MSG_BusyPGPrunning), "", 0, 0);
  2464.           strmfp(command, C->PGPCmdPath, progname);
  2465.           strcat(command, " >" PGPLOGFILE " ");
  2466.           strcat(command, options);
  2467.           error = SystemTags(command, SYS_Input, fhi, SYS_Output, fho, NP_StackSize, C->StackSize, TAG_DONE);
  2468.           Close(fho);
  2469.           BusyEnd;
  2470.         }
  2471.         Close(fhi);
  2472.    }
  2473.    if (error > 0 && !(flags & NOERRORS)) ER_NewError(GetStr(MSG_ER_PGPreturnsError), command, PGPLOGFILE);
  2474.    if (error < 0) ER_NewError(GetStr(MSG_ER_PGPnotfound), C->PGPCmdPath, NULL);
  2475.    if (!error && !(flags & KEEPLOG)) DeleteFile(PGPLOGFILE);
  2476.    return error;
  2477. }
  2478. ///
  2479. /// AppendToLogfile
  2480. //  Appends a line to the logfile
  2481. LOCAL void AppendToLogfile(int id, char *text, void *a1, void *a2, void *a3, void *a4)
  2482. {
  2483.    FILE *fh;
  2484.    char logfile[SIZE_PATHFILE], filename[SIZE_FILE];
  2485.    if (!C->LogAllEvents && (id < 30 || id > 49)) return;
  2486.    if (C->SplitLogfile)
  2487.    {
  2488.       struct ClockData cd;
  2489.       Amiga2Date(GetDateStamp(), &cd);
  2490.       sprintf(filename, "YAM-%s%ld.log", months[cd.month-1], cd.year);
  2491.    }
  2492.    else strcpy(filename, "YAM.log");
  2493.    strmfp(logfile, *C->LogfilePath ? C->LogfilePath : G->ProgDir, filename);
  2494.    if ((fh = fopen(logfile, "a")))
  2495.    {
  2496.       fprintf(fh, "%s [%02ld] ", DateStamp2String(NULL, DSS_DATETIME), id);
  2497.       fprintf(fh, text, a1, a2, a3, a4);
  2498.       fprintf(fh, "\n");
  2499.       fclose(fh);
  2500.    }
  2501. }
  2502. ///
  2503. /// AppendLog
  2504. //  Appends a line to the logfile, depending on log mode
  2505. void AppendLog(int id, char *text, void *a1, void *a2, void *a3, void *a4)
  2506. {
  2507.    if (C->LogfileMode != 0) AppendToLogfile(id, text, a1, a2, a3, a4);
  2508. }
  2509. void AppendLogNormal(int id, char *text, void *a1, void *a2, void *a3, void *a4)
  2510. {
  2511.    if (C->LogfileMode == 1) AppendToLogfile(id, text, a1, a2, a3, a4);
  2512. }
  2513. void AppendLogVerbose(int id, char *text, void *a1, void *a2, void *a3, void *a4)
  2514. {
  2515.    if (C->LogfileMode == 2) AppendToLogfile(id, text, a1, a2, a3, a4);
  2516. }
  2517. ///
  2518. /// Busy
  2519. //  Displays busy message and sleep pointer
  2520. int BusyLevel = 0;
  2521. void Busy(char *text, char *parameter, int cur, int max)
  2522. {
  2523.    static char infotext[SIZE_DEFAULT];
  2524.    if (text)
  2525.    {
  2526.       if (*text)
  2527.       {
  2528.          sprintf(infotext, text, parameter);
  2529.          if (G->MA && !BusyLevel)
  2530.          {
  2531.             set(G->MA->GUI.GA_INFO, MUIA_Gauge_InfoText, infotext);
  2532.             set(G->MA->GUI.GA_INFO, MUIA_Gauge_Max, max);
  2533.          }
  2534.          BusyLevel++;
  2535.          set(G->App, MUIA_Application_Sleep, TRUE);
  2536.       }
  2537.       else
  2538.       {
  2539.          set(G->App, MUIA_Application_Sleep, FALSE);
  2540.          if (BusyLevel) --BusyLevel;
  2541.          if (G->MA && !BusyLevel)
  2542.          {
  2543.             set(G->MA->GUI.GA_INFO, MUIA_Gauge_InfoText, "");
  2544.             set(G->MA->GUI.GA_INFO, MUIA_Gauge_Current, 0);
  2545.          }
  2546.       }
  2547.    }
  2548.    else
  2549.    {
  2550.       set(G->MA->GUI.GA_INFO, MUIA_Gauge_Current, cur);
  2551.    }
  2552. }
  2553. ///
  2554. /// DisplayStatistics
  2555. //  Calculates folder statistics and update mailbox status icon
  2556. void DisplayStatistics(struct Folder *fo)
  2557. {
  2558.     struct Mail *mail;
  2559.     BOOL check = FALSE;
  2560.     struct Folder *actfo = FO_GetCurrentFolder();
  2561.     static char apptit[SIZE_DEFAULT/2];
  2562.  
  2563.     // If the parsed argument is NULL we set want to show the statistics from the actual folder
  2564.     if (!fo) fo = actfo;
  2565.  
  2566.     if (fo == (struct Folder *)-1)
  2567.   {
  2568.       fo = FO_GetFolderByType(FT_INCOMING, NULL);
  2569.     check = TRUE;
  2570.   }
  2571.  
  2572.   for (mail = fo->Messages, fo->Unread = fo->New = 0; mail; mail = mail->Next)
  2573.     {
  2574.       if (mail->Status == STATUS_NEW) { fo->New++; fo->Unread++; }
  2575.     if (mail->Status == STATUS_UNR) fo->Unread++;
  2576.   }
  2577.  
  2578.     DoMethod(G->MA->GUI.NL_FOLDERS, MUIM_NList_Redraw, FO_GetFolderPosition(fo), TAG_DONE);
  2579.  
  2580.   if (fo == actfo)
  2581.   {
  2582.       MA_SetMessageInfoFunc();
  2583.     MA_SetFolderInfoFunc();
  2584.   }
  2585.  
  2586.   // if the folder that statistic has changed is the incoming folder we also have to change the AppIcon accordingly
  2587.   if (fo->Type == FT_INCOMING && !G->AppIconQuiet)
  2588.   {
  2589.       if (check || fo->New != G->NewMsgs || fo->Unread != G->UnrMsgs || fo->Total != G->TotMsgs)
  2590.       {
  2591.       // we set the mode accordingly to the status of the folder (new/check/old)
  2592.       int mode = fo->Total ? (fo->New ? 2 : 1) : 0;
  2593.  
  2594.       if (G->TR && G->TR->Checking) mode = 3;
  2595.       SPrintF(apptit, GetStr(MSG_APPICON_STATS), fo->New, fo->Unread, fo->Total);
  2596.  
  2597.       // We first have to remove the appicon before we can change it
  2598.       if (G->AppIcon)
  2599.       {
  2600.           RemoveAppIcon(G->AppIcon);
  2601.         G->AppIcon = NULL;
  2602.       }
  2603.  
  2604.       // Now we create the new AppIcon and display it
  2605.       if (G->DiskObj[mode])
  2606.       {
  2607.          struct DiskObject *dobj=G->DiskObj[mode];
  2608.          G->AppIcon = AddAppIconA(0, 0, (STRPTR)apptit, G->AppPort, NULL, dobj, NULL);
  2609.       }
  2610.  
  2611.       G->NewMsgs = fo->New;
  2612.       G->UnrMsgs = fo->Unread;
  2613.       G->TotMsgs = fo->Total;
  2614.        }
  2615.    }
  2616. }
  2617. ///
  2618. /// CheckPrinter
  2619. //  Checks if printer is ready
  2620. BOOL CheckPrinter(void)
  2621. {
  2622.    struct MsgPort *PrintPort;
  2623.    struct IOStdReq *PrintIO;
  2624.    UWORD  Result = 0;
  2625.    char  _PrinterDeviceName[] = "printer.device";
  2626.    long  _PrinterDeviceUnit = 0;
  2627.    char *error = NULL;
  2628.  
  2629.    if ((PrintPort = CreateMsgPort()))
  2630.    {
  2631.       PrintPort->mp_Node.ln_Name = "YAM PrintPort";
  2632.       if ((PrintIO = CreateIORequest(PrintPort, sizeof(struct IOStdReq))))
  2633.       {
  2634.          if (!(OpenDevice((STRPTR)_PrinterDeviceName, _PrinterDeviceUnit, (struct IORequest *)PrintIO, 0)))
  2635.          {
  2636.             PrintIO->io_Message.mn_ReplyPort = PrintPort;
  2637.             PrintIO->io_Command = PRD_QUERY;
  2638.             PrintIO->io_Data = &Result;
  2639.             DoIO((struct IORequest *)PrintIO);
  2640.                 if(PrintIO->io_Actual == 1)        // parallel port printer?
  2641.                 {
  2642.                 if (((Result>>8) & 3) == 0) error = NULL;                            // no error
  2643.                 else if ((Result>>8) & 01) error = GetStr(MSG_UT_NoPaper);    // /POUT asserted
  2644.                 else error = GetStr(MSG_UT_NoPrinter);                                // /BUSY (hopefully no RingIndicator interference)
  2645.                 } else error = NULL;                    // can't determine status of serial printers
  2646.             CloseDevice((struct IORequest *)PrintIO);
  2647.          }
  2648.          DeleteIORequest((struct IORequest *)PrintIO);
  2649.       }
  2650.       DeleteMsgPort(PrintPort);
  2651.    }
  2652.    if (error) if (!MUI_Request(G->App, NULL, 0, GetStr(MSG_ErrorReq), GetStr(MSG_OkayCancelReq), error)) return False;
  2653.    return True;
  2654. }
  2655. ///
  2656. /// PlaySound
  2657. //  Plays a sound file using datatypes
  2658. void PlaySound(char *filename)
  2659. {
  2660.    if (DataTypesBase)
  2661.    {
  2662.       struct dtTrigger Play = { DTM_TRIGGER, NULL, STM_PLAY, NULL };
  2663.       Object *sound;
  2664.       BYTE sig;
  2665.       if ((sound = NewDTObject((APTR)filename, DTA_GroupID, GID_SOUND, SDTA_Volume, 64, SDTA_Cycles, 1, TAG_DONE)))
  2666.       {
  2667.          if ((sig = AllocSignal(-1)) >= 0)
  2668.          {
  2669.             if (SetDTAttrs(sound, NULL, NULL, SDTA_SignalTask, FindTask(NULL), SDTA_SignalBit, 1<<sig, TAG_END) == 2)
  2670.             {
  2671.                DoDTMethodA(sound, NULL, NULL, (Msg)&Play);
  2672.                Wait(1<<sig);
  2673.             }
  2674.             else
  2675.             {
  2676.                ULONG length = 0, period = 394, cycles = 1, frequency, seconds;
  2677.                GetDTAttrs(sound, SDTA_SampleLength, &length, SDTA_Period, &period, SDTA_Cycles, &cycles, TAG_END);
  2678.                if (length > 131072) length = 131072;
  2679.                frequency = (ULONG)(SysBase->ex_EClockFrequency * 5) / period;
  2680.                seconds = (length * cycles) / frequency + 1;
  2681.                DoDTMethodA(sound, NULL, NULL, (Msg)&Play);
  2682.                Delay(seconds * 50);
  2683.             }
  2684.             FreeSignal(sig);
  2685.          }
  2686.          DisposeDTObject(sound);
  2687.       }
  2688.    }
  2689. }
  2690. ///
  2691. /// MatchExtension
  2692. //  Matches a file extension against a list of extension
  2693. BOOL MatchExtension(char *fileext, char *extlist)
  2694. {
  2695.    while ((extlist = strtok(extlist, " ")))
  2696.    {
  2697.       if (!stricmp(extlist, fileext)) return TRUE;
  2698.       extlist = NULL;
  2699.    }
  2700.    return FALSE;
  2701. }
  2702. ///
  2703. /// IdentifyFileDT
  2704. //  Detects the file type using datatypes.library
  2705. LOCAL char *IdentifyFileDT(char *fname)
  2706. {
  2707.    static char ctype[SIZE_CTYPE], *type = NULL;
  2708.    struct Library *DataTypesBase = OpenLibrary("datatypes.library", 39);
  2709.    strcpy(ctype, "application/octet-stream");
  2710.    if (DataTypesBase)
  2711.    {
  2712.       BPTR lock;
  2713.       if ((lock = Lock(fname, ACCESS_READ)))
  2714.       {
  2715.          struct DataType *dtn;
  2716.          if ((dtn = ObtainDataTypeA(DTST_FILE, (APTR)lock, NULL)))
  2717.          {
  2718.             struct DataTypeHeader *dth = dtn->dtn_Header;
  2719.             switch (dth->dth_GroupID)
  2720.             {
  2721.                case GID_SYSTEM:     break;
  2722.                case GID_DOCUMENT:   type = "application"; break;
  2723.                case GID_TEXT:       type = "text"; break;
  2724.                case GID_SOUND:
  2725.                case GID_INSTRUMENT: type = "audio"; break;
  2726.                case GID_PICTURE:    type = "image"; break;
  2727.                case GID_MOVIE:
  2728.                case GID_ANIMATION:  type = "video"; break;
  2729.             }
  2730.             if (type) sprintf(ctype, "%s/x-%s", type, dth->dth_BaseName);
  2731.             ReleaseDataType(dtn);
  2732.          }
  2733.          UnLock (lock);
  2734.       }
  2735.       CloseLibrary(DataTypesBase);
  2736.    }
  2737.    return ctype;
  2738. }
  2739. ///
  2740. /// IdentifyFile
  2741. //  Detects the file type by analyzing file extension and contents
  2742. char *IdentifyFile(char *fname)
  2743. {
  2744.    char *ctype = "";
  2745.    long bits = FileProtection(fname);
  2746.    FILE *fh;
  2747.  
  2748.    if ((fh = fopen(fname, "r")))
  2749.    {
  2750.       int i, len;
  2751.       char buffer[SIZE_LARGE], *ext;
  2752.  
  2753.       len = fread(buffer, 1, SIZE_LARGE-1, fh);
  2754.       buffer[len] = 0;
  2755.       fclose(fh);
  2756.       if ((ext = strrchr(fname, '.'))) ++ext; else ext = "--";
  2757.       if (!stricmp(ext, "htm") || !stricmp(ext, "html"))
  2758.          ctype = ContType[CT_TX_HTML];
  2759.       else if (!strnicmp(buffer, "@database", 9) || !stricmp(ext, "guide"))
  2760.          ctype = ContType[CT_TX_GUIDE];
  2761.       else if (!stricmp(ext, "ps") || !stricmp(ext, "eps"))
  2762.          ctype = ContType[CT_AP_PS];
  2763.       else if (!stricmp(ext, "rtf"))
  2764.          ctype = ContType[CT_AP_RTF];
  2765.       else if (!stricmp(ext, "lha") || !strncmp(&buffer[2], "-lh5-", 5))
  2766.          ctype = ContType[CT_AP_LHA];
  2767.       else if (!stricmp(ext, "lzx") || !strncmp(buffer, "LZX", 3))
  2768.          ctype = ContType[CT_AP_LZX];
  2769.       else if (!stricmp(ext, "zip"))
  2770.          ctype = ContType[CT_AP_ZIP];
  2771.       else if (*((long *)buffer) >= HUNK_UNIT && *((long *)buffer) <= HUNK_INDEX)
  2772.          ctype = ContType[CT_AP_AEXE];
  2773.       else if (!stricmp(ext, "rexx") || !stricmp(ext+strlen(ext)-2, "rx"))
  2774.          ctype = ContType[CT_AP_REXX];
  2775.       else if (!strncmp(&buffer[6], "JFIF", 4))
  2776.          ctype = ContType[CT_IM_JPG];
  2777.       else if (!strncmp(buffer, "GIF8", 4))
  2778.          ctype = ContType[CT_IM_GIF];
  2779.       else if (!strnicmp(ext, "png",4) || !strncmp(&buffer[1], "PNG", 3))
  2780.          ctype = ContType[CT_IM_PNG];
  2781.       else if (!strnicmp(ext, "tif",4))
  2782.          ctype = ContType[CT_IM_TIFF];
  2783.       else if (!strncmp(buffer, "FORM", 4) && !strncmp(&buffer[8], "ILBM", 4))
  2784.          ctype = ContType[CT_IM_ILBM];
  2785.       else if (!stricmp(ext, "au") || !stricmp(ext, "snd"))
  2786.          ctype = ContType[CT_AU_AU];
  2787.       else if (!strncmp(buffer, "FORM", 4) && !strncmp(&buffer[8], "8SVX", 4))
  2788.          ctype = ContType[CT_AU_8SVX];
  2789.       else if (!stricmp(ext, "wav"))
  2790.          ctype = ContType[CT_AU_WAV];
  2791.       else if (!stricmp(ext, "mpg") || !stricmp(ext, "mpeg"))
  2792.          ctype = ContType[CT_VI_MPG];
  2793.       else if (!stricmp(ext, "qt") || !stricmp(ext, "mov"))
  2794.          ctype = ContType[CT_VI_MOV];
  2795.       else if (!strncmp(buffer, "FORM", 4) && !strncmp(&buffer[8], "ANIM", 4))
  2796.          ctype = ContType[CT_VI_ANIM];
  2797.       else if (!stricmp(ext, "avi"))
  2798.          ctype = ContType[CT_VI_AVI];
  2799.       else if (stristr(buffer, "\nFrom:"))
  2800.          ctype = ContType[CT_ME_EMAIL];
  2801.       else
  2802.       {
  2803.          for (i = 1; i < MAXMV; i++) if (C->MV[i])
  2804.             if (MatchExtension(ext, C->MV[i]->Extension)) ctype = C->MV[i]->ContentType;
  2805.       }
  2806.       if (!*ctype)
  2807.       {
  2808.          int notascii = 0;
  2809.          for (i = 0; i < len; i++)
  2810.             if ((int)buffer[i] < 32 || (int)buffer[i] > 127)
  2811.                if (buffer[i] != '\t' && buffer[i] != '\n') notascii++;
  2812.          if (notascii < len/10) ctype =  ContType[(bits&FIBF_SCRIPT) ? CT_AP_SCRIPT : CT_TX_PLAIN];
  2813.          else ctype = IdentifyFileDT(fname);
  2814.       }
  2815.    }
  2816.    return ctype;
  2817. }
  2818. ///
  2819. /// LoadTranslationTable
  2820. //  Load a translation table into memory
  2821. BOOL LoadTranslationTable(struct TranslationTable **tt, char *file)
  2822. {
  2823.    FILE *fp;
  2824.    if (*tt) free(*tt);
  2825.    if (!*file) return FALSE;
  2826.    if (!(*tt = calloc(1,sizeof(struct TranslationTable)))) return FALSE;
  2827.    if ((fp = fopen(file, "r")))
  2828.    {
  2829.       UBYTE buf[SIZE_DEFAULT], *p;
  2830.       int i;
  2831.       for (i = 0; i < 256; i++) (*tt)->Table[i] = (UBYTE)i;
  2832.       stccpy((*tt)->File, file, SIZE_PATHFILE);
  2833.       fgets(buf, SIZE_DEFAULT, fp);
  2834.       if (!strncmp(buf, "YCT1", 4))
  2835.       {
  2836.          fgets((*tt)->Name, SIZE_DEFAULT, fp);
  2837.          if ((p = strchr((*tt)->Name,'\n'))) *p = 0;
  2838.          while (fgets(buf, SIZE_DEFAULT, fp))
  2839.             if (!strnicmp(buf, "from", 4)) stccpy((*tt)->SourceCharset, Trim(&buf[5]), SIZE_CTYPE);
  2840.             else if  (!strnicmp(buf, "to", 2)) stccpy((*tt)->DestCharset, Trim(&buf[3]), SIZE_CTYPE);
  2841.             else if (!strnicmp(buf, "header", 6)) (*tt)->Header = TRUE;
  2842.             else if (!strnicmp(buf, "author", 6));
  2843.             else if (strchr(buf, '='))
  2844.             {
  2845.                int source, dest;
  2846.                p = buf;
  2847.                if (*p == '$') stch_i(&p[1], &source); else source = (int)*p;
  2848.                while (*p++ != '=');
  2849.                if (*p == '$') stch_i(&p[1], &dest); else dest = (int)*p;
  2850.                if (source >= 0 && source <= 0xFF && dest >= 0 && dest <= 0xFF) (*tt)->Table[source] = (UBYTE)dest;
  2851.             }
  2852.          fclose(fp);
  2853.          return TRUE;
  2854.       }
  2855.       fclose(fp);
  2856.    }
  2857.    ER_NewError(GetStr(MSG_ER_ErrorTTable), file, NULL);
  2858.    free(*tt); *tt = NULL;
  2859.    return FALSE;
  2860. }
  2861. ///
  2862. /// ExecuteCommand
  2863. //  Executes a DOS command
  2864. BOOL ExecuteCommand(char *cmd, BOOL asynch, BPTR outdef)
  2865. {
  2866.    BPTR in, out, path;
  2867.    int ret;
  2868.    switch (outdef)
  2869.    {
  2870.       case NULL:    in = Input();out = Output(); break;
  2871.       case OUT_NIL: out = Open("NIL:", MODE_NEWFILE); in = Open("NIL:", MODE_OLDFILE); break;
  2872.       default:      out = outdef; in = Open("NIL:", MODE_OLDFILE); break;
  2873.    }
  2874.    if (!outdef) asynch = FALSE;
  2875.    if (_WBenchMsg)
  2876.    {
  2877.       path = CloneWorkbenchPath(_WBenchMsg);
  2878.       if ((ret = SystemTags(cmd, SYS_Input,in, SYS_Output,out, NP_Path,path, NP_StackSize,C->StackSize, SYS_Asynch,asynch, TAG_DONE)) == -1) FreeWorkbenchPath(path);
  2879.    }
  2880.    else ret = SystemTags(cmd, SYS_Input,in, SYS_Output,out, NP_StackSize,C->StackSize, SYS_Asynch,asynch, TAG_DONE);
  2881.    if (ret == -1 && asynch && outdef) { Close(out); Close(in); }
  2882.    return (BOOL)(!ret);
  2883. }
  2884. ///
  2885. /// GetSimpleID
  2886. //  Returns a unique number
  2887. int GetSimpleID(void)
  2888. {
  2889.    static int num = 0;
  2890.    return ++num;
  2891. }
  2892. ///
  2893. /// GotoURL
  2894. //  Loads an URL using an ARexx script or openurl.library
  2895. void GotoURL(char *url)
  2896. {
  2897.    if (C->RX[MACRO_URL].Script[0])
  2898.    {
  2899.       char newurl[SIZE_LARGE];
  2900.       sprintf(newurl, "%c%s%c", '"', url, '"');
  2901.       MA_StartMacro(MACRO_URL, newurl);
  2902.    }
  2903.    else if ((OpenURLBase = OpenLibrary("openurl.library", 1)))
  2904.    {
  2905.       URL_Open(url, TAG_DONE);
  2906.       CloseLibrary(OpenURLBase);
  2907.    }
  2908. }
  2909. ///
  2910.  
  2911. /// strtok_r()
  2912. // Reentrant version of stdlib strtok()
  2913. // Call like this:
  2914. // char *next=input, *token, breakstring[]=", ";
  2915. // do    { token = strtok_r(&next,breakstring); /* ... */ } while(next);
  2916. char *strtok_r(char **s, char *brk)
  2917. {
  2918. char *p,*ret;
  2919.  
  2920.     if((s == NULL) || (*s == NULL) || (brk == NULL))
  2921.         return NULL;
  2922.  
  2923.     /* find break character */
  2924.     if((p = strpbrk(*s,brk)))
  2925.     {
  2926.         /* if found, terminate string there */
  2927.         *p = '\0';
  2928.  
  2929.         /* scan forward to next non-break */
  2930.         do { p++; } while(*p && (strchr(brk,*p) != NULL));
  2931.  
  2932.         /* if *p is a nullbyte, then no more tokens */
  2933.         if(*p == '\0') p = NULL;
  2934.  
  2935.         /* save current *s to return it */
  2936.         ret = *s;
  2937.  
  2938.         /* and let *s point to first non-break */
  2939.         *s = p;
  2940.  
  2941.         return ret;
  2942.     }
  2943.  
  2944.     /* no break character found - *s gets NULL */
  2945.     ret = *s;
  2946.     *s = NULL;
  2947.  
  2948.     return ret;
  2949. }
  2950. ///
  2951.  
  2952. /*** REXX interface support ***/
  2953.  
  2954. /// InsertAddresses
  2955. //  Appends an array of addresses to a string gadget
  2956. void InsertAddresses(APTR obj, char **addr, BOOL add)
  2957. {
  2958.    char *buf;
  2959.    get(obj, MUIA_String_Contents, &buf);
  2960.    if (*buf && add) DoMethod(obj, MUIM_BetterString_Insert, ", ", MUIV_BetterString_Insert_EndOfString);
  2961.    else setstring(obj, "");
  2962.    DoMethod(obj, MUIM_BetterString_Insert, *addr, MUIV_BetterString_Insert_EndOfString);
  2963.    while (*++addr)
  2964.    {
  2965.       DoMethod(obj, MUIM_BetterString_Insert, ", ", MUIV_BetterString_Insert_EndOfString);
  2966.       DoMethod(obj, MUIM_BetterString_Insert, *addr, MUIV_BetterString_Insert_EndOfString);
  2967.    }
  2968. }
  2969. ///
  2970. /// AllocReqText
  2971. //  Prepare multi-line text for requesters, converts \n to line breaks
  2972. char *AllocReqText(char *s)
  2973. {
  2974.    char *d, *reqtext;
  2975.    d = reqtext = calloc(strlen(s)+1, 1);
  2976.    while (*s)
  2977.       if (*s == '\\' && s[1] == 'n') { *d++ = '\n'; s++; s++; }
  2978.       else *d++ = *s++;
  2979.    return reqtext;
  2980. }
  2981. ///
  2982.  
  2983. /// putCharFunc
  2984. //  Hook used by FormatString()
  2985. void SAVEDS ASM putCharFunc(REG(a0, struct Hook *hook), REG(a1, char c), REG(a2, struct Locale *locale))
  2986. {
  2987.     char **tmp;
  2988.  
  2989.     ((char *)hook->h_Data)[0] = c;
  2990.     tmp = (char **)(&hook->h_Data);
  2991.     (*tmp)++;
  2992. }
  2993. MakeHook(putCharHook, putCharFunc);
  2994. ///
  2995.  
  2996. /// SPrintF
  2997. //  sprintf() replacement with Locale support
  2998.  
  2999. void SPrintF(char *outstr, char *fmtstr, ...)
  3000. {
  3001.     struct Hook hook;
  3002. #ifdef __PPC__
  3003.     va_list ap;
  3004.     ULONG arg[32];
  3005.     int args = 0, i;
  3006.  
  3007.     for (i=0; fmtstr[i] != '\0'; i++) {
  3008.         if (fmtstr[i] == '%' && fmtstr[i+1] != '%') args++;
  3009.     }
  3010.  
  3011.     va_start(ap, fmtstr);
  3012.     for (i=0; i<args; i++) {
  3013.         arg[i] = va_arg(ap, ULONG);
  3014.     }
  3015.     va_end(ap);
  3016. #endif
  3017.  
  3018.     InitHook(&hook, putCharFunc, outstr);
  3019.  
  3020. #ifdef __PPC__
  3021.     FormatString(G->Locale, fmtstr, &arg[0], &hook);
  3022. #else
  3023.     FormatString(G->Locale, fmtstr, &fmtstr+1, &hook);
  3024. #endif
  3025. }
  3026. ///
  3027.